/************************************************************************************************
 *   深圳市摩西尔电子有限公司 @版本所有@
 *
 *   此文件为 webUI 箱体
 *
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2019.12.03
 *      内容 : 所有代码
 *   2. 类型 : 添加
 *      作者 : 巫昭雯
 *      时间 : 2019.11.28
 *      内容 : 在以下代码中添加简易模式设置; 带obj_item_checkbox_easy_mode判断; dom 值 === true 表示简易模式
 *************************************************************************************************/

/* exported mc_box */
/* exported mc_mod_sizeup */
/* exported mc_empty_arr_select_mod*/
/* exported mc_mod_adhesions_switch*/
/* exported mc_set_canvasbg_size */
/* exported mc_canvasbg_show_size */
/* exported mc_mod_check */
/* exported mc_adapt_canvasbg_size */
/* exported get_box_scale_multiple */
/* exported mc_get_transform_val */
/* exported update_show_name_val */
/* exported init_mc_move_layer */
/* exported mc_set_replace_mod */
/* exported mc_set_mod_del */
/* exported mc_set_level_mod */
/* exported mc_set_vertical_mod */
/* exported mc_set_level_align_mod */


/* global $ */
/* global layer */
/* global get_obj_box */
/* global b_connection */
/* global g_obj_save_log */
/* global g_obj_side_show_name */
/* global change_block_bgc */
/* global menu_move */
/* global mc_close_menu */
/* global mc_lang_undo_module */
/* global mc_lang_redo_module */
/* global clearBubble */
/* global mc_get_top_fun */
/* global adapt_canvas_size */
/* global update_canvas_h */
/* global mc_nwjs_check_support */
/* global arr_mod_selected_copy */
/* global mc_lang_copy_module */
/* global mc_updata_selected_copy */
/* global set_easy_mode */
/* global obj_item_checkbox_easy_mode */
/* global ui_easy_mode_size */
/* global mc_util_round */
/* global obj_box_coordinate_ruler */
/* global mc_easy_mode_update_pos */
/* global obj_mousedown */
/* global has_ruler_and_method */
/* global mc_layout_operate_format_data */
/* global mc_transform_id_data */
/* global mc_get_create_module_msg */
/* global mc_layout_operate */
/* global update_module_msg_txt */
/* global mc_compare_update_module_msg_txt */
/* global mc_set_zoom_slider */
/* global mc_box_mouseevent_bubble */
/* global mc_select_end_show_menu */
/* global mc_get_top_data */
/* global mc_menu_exhibit */
/* global mc_set_mouse_pot */
/* global mc_filter_tool */
/* global mc_update_module_size */

// 模块信息---------------------------------
// obj_module_msg = {
//     ID-模块元素ID: {
//         o_pot: 位置信息子元素js
//         o_size: 大小信息子元素js
//         str_pot: 模块位置信息字串 L, T
//         str_size: 模块大小信息字串 w X h
//     },,,
// }
var obj_module_msg = {};
var g_ui_mod_cnt = -1;
// 编辑开关 true正在编辑
var b_progress_edit = false;
var b_istouch = mc_get_top_data("B_ISTOUCH");
var obj_event_type = mc_judge_event_type();
var b_box_select = false;

mc_set_canvas_msg_style();
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取动态ID
 * 参数:
 *    无
 * 返回：
 *    @return { Promise<String> } 动态ID
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2019.11.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_id() {
    g_ui_mod_cnt++;
    return new Date().getTime() + (Math.random() * 1000).toFixed(0) + g_ui_mod_cnt;
}

// 定义传递函数
var g_str_attr_lab_val_chg = "on_val_chg";
var g_str_attr_operate_mod_end = "operate_mod_end";
var g_obj_func_name_map = {};
// 排列位置
var ui_left = 0;
var ui_top = 0;
// 记录放大箱体到达临界点次数
// var ui_sizeup = 0;
// 判断是否按下ctrl+c
// var b_is_copy = false;
// 保存被选中的模组（按顺序）
var arr_select_mod = [];
// 拖拽构造函数
// eslint-disable-next-line no-unused-vars
var use_draw = null;
// eslint-disable-next-line no-unused-vars
var select_menu = null;
// 是否创建canvas格子 默认创建
var b_create_grid = true;
// 当前页面显示画布大小
var ui_canvasbg_size_w = 4096;
var ui_canvasbg_size_h = 2160;
// 当前画布盒子缩放倍数 缩放范围1-100 设置时需/100 大屏0.1-100
var ui_mod_box_scale = 100;
// 缩放步进 大屏0.1
var ui_box_scale_step = 1;
// 显示信息参数 [chip,pot,size,hub,idx,card_name,line]
var arr_info_disp = [1, 1, 1, 1, 1, 1, 1, 1];
// 视窗显示中心坐标
var ui_box_center_x = 0;
var ui_box_center_y = 0;
// 模块中心点坐标
var obj_module_center_xy = null;
// 模组对应亮点格子数组 [{mod_id:array-对应亮点格子数组, grig:string-创建格子宽度, img_url:string-未选中背景, select_url:string-选中背景},,]
var arr_get_img_url = [];

var b_ctrl_select = false;
var str_mod_attr_easy_mode = "b_easy_mode";
// 鼠标位置 缩放鼠标按下位置为基准，抬起后才可重新获取位置
var obj_mouse_pot = {
    b_keyup: true,
    ui_clientx: 0,
    ui_clienty: 0
};

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    创建画布及模块
 * 参数:
 *    @param { Promise<String> } str_div_id 父盒子ID jq方式传入 如#BOX_ID
 * 返回：
 *    无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.03.16
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_box(str_div_id) {
    $(str_div_id).css("overflow", "auto");
    // 嵌套框class类
    var ary_box_class = ["mc_mod_box"];
    // 模组样式
    var ary_mod_style = [];
    // 模组class类
    var ary_mod_class = ["mc_mod"];
    // 模组宽高 格数
    var uni_mod_wg = 6;
    var uni_mod_hg = 6;
    // 默认创建最大格子宽度
    var ui_max_grid = 26;
    // 画布最小缩放倍数
    var ui_min_scale = 4;
    // 模组起始位置 格子数（设置显示位置）
    var ui_pot_left = 0;
    var ui_pot_top = 0;
    // 小模组名称
    var str_mod_item_id = "";
    var str_show_name = "";
    // 模组中心圆的值
    var str_mod_center_val = "?";
    // 是否调用框选
    var b_select_fn = true;
    // 芯片信息
    var str_chip_name = "";
    // card idx
    var str_card_idx = "";
    // list idx
    var str_list_idx = "?";
    // 变换参数数组 ["X缩放","Y缩放","旋转角度","镜像类型"]
    var ary_transform = [];
    // 是否开启描点 默认开启
    var ui_tracing_point = 1;
    // 创建字串 连线ID对象
    // var obj_module_line_id = {};
    // 创建字串 未设置连线ID对象
    var arr_default_module_id = [];

    this.on_val_chg = function () { };
    // 拖拽结束回调
    this.operate_mod_end = function () { };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    清空参数
    * 参数:
    *    NA
    * 返回：
    *    @return { Promise<Boolean> }
    *    true 清空
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.9.11
    *      内容 : 所有代码
    ************************************************************************************************/
    this.clear_box_param = function () {
        ary_mod_style = [];
        ary_mod_class = ["mc_mod"];
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    获取模块字串
    * 参数:
    *    @param { Promise<Object> } obj_params 参数对象
    *    @param { Promise<Object> } obj_module_line_id 连线对象
    *    @param { Promise<String> } str_id str_id 创建模块id /可为空 此项传入时不校验参数
    * 备注：
    *   参数 obj_params = {
    *           width: String/Number 模块宽度(格子数),
    *           height: String/Number 模块高度(格子数),
    *           left: String/Number 模块左边距(格子数),
    *           top: String/Number 模块上边距(格子数),
    *           module_class: Array:[className:string,,] 需要额外添加的class名数组,
    *           module_style: Array:[[width:XXpx],,,] 需要额外添加的样式,
    *           center_hub_val: string 中心小圆值
    *           module_id: string 使用模块名 "MC_BOX_0"/"MC_MOD_0",
    *           module_list_idx: String 模块在连线队列中的位置下标 mod_list_idx值
    *           module_card_idx: String 箱体卡位置标识 card_idx值
    *           transform_msg: ["X缩放","Y缩放","旋转角度","镜像类型","裁剪字串"] 变换参数
    *           ctrlchip_name: String 芯片信息
    *           module_show_name: String 使用模块名
    *           attr: String 额外添加属性
    *       }
    * 返回：
    *    @return { Promise<Boolean> }
    *     {str_html:模块字串，obj_module_line_id:当前连线id}
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.9.11
    *      内容 : 所有代码
    ************************************************************************************************/
    this.get_module_html_str = function (obj_params, obj_module_line_id, str_id) {
        if ("[object Object]" !== Object.prototype.toString.call(obj_params) || "[object Object]" !== Object.prototype.toString.call(obj_module_line_id)) {
            return false;
        }
        var str_grid = document.getElementById("mod_box_next").getAttribute("grid_w");
        var obj_check_param = str_id ? obj_params : mc_check_construct_module_params(obj_params, Number(str_grid));
        var str_center_hub_val = obj_check_param.center_hub_val;
        var str_class_list = obj_check_param.module_class.trim();
        var str_img_url = "";
        var str_ctrlchip_html = "";
        var str_card_index = "";
        // 转换信息显示样式
        var arr_indo_disp_style = mc_info_disp_style();
        var ui_child_transform = 1 / (ui_mod_box_scale / 100);
        // canvas bg
        var obj_canvasbg = mc_construct_moduele_canvas_bg(str_grid, obj_check_param.module_id);
        var str_easy_mode = str_mod_attr_easy_mode + "=false";
        var str_mod_id = str_id || "mod" + mc_get_id();
        var ui_width = Number(obj_check_param.width);
        var ui_height = Number(obj_check_param.height);

        var str_pot = obj_check_param.left + "," + obj_check_param.top;
        var arr_transform = obj_check_param.transform_msg;
        var str_size = ui_width + "X" + ui_height;
        var str_style_offset = "";
        var str_style_transform = "";
        var str_style_child_transform = "";
        var str_transform_mag_attr = "";

        // save str_size str_pot
        // mc_save_undom_module_msg(str_mod_id, ui_width / (isNaN(Number(arr_transform[0])) ? 1 : Number(arr_transform[0])) + "X" + (ui_height / ( isNaN(Number(arr_transform[1])) ? 1 : Number(arr_transform[1]))), str_pot);
        mc_save_undom_module_msg(str_mod_id, str_size, str_pot);
        // 变换设置
        if (arr_transform && 4 <= arr_transform.length) {
            str_grid = Number(str_grid);
            var arr_transform_copy = $.extend(true, [], arr_transform);

            arr_transform_copy.push(ui_width , ui_height);
            // arr_transform_copy.push(ui_width / (isNaN(Number(arr_transform[0])) ? 1 : Number(arr_transform[0])),ui_height / ( isNaN(Number(arr_transform[1])) ? 1 : Number(arr_transform[1])));
            var obj_set_transform = mc_undom_rotate_sacle_apply(str_mod_id, arr_transform_copy, str_grid);

            str_transform_mag_attr = "transform_msg=" + obj_set_transform.str_transform_msg;
            str_style_transform = obj_set_transform.str_transform_val;
            str_style_child_transform = obj_set_transform.str_transform_child_val;
            str_style_offset = "left:" + obj_set_transform.left * Number(str_grid) + "px;top:" + obj_set_transform.top * Number(str_grid) + "px;";
        } else {
            str_style_offset = "left:" + obj_check_param.left * Number(str_grid) + "px;top:" + obj_check_param.top * Number(str_grid) + "px;";
        }

        if (obj_canvasbg) {
            str_img_url = "background-image:url(" + obj_canvasbg.no_select + ");";
            mc_save_mod_canvasbg(str_mod_id, obj_canvasbg.select_tip, obj_canvasbg.no_select);
        }
        if (!b_create_grid) {
            str_img_url = "background-color:#8C9BF0;";
            str_ctrlchip_html = "<div class='chip_name' style='" + str_style_child_transform + arr_indo_disp_style[1] + "'>" + obj_check_param.ctrlchip_name + "</div>";
            str_card_index = "<div class='mc_mod_right_bto' style='transform:scale(" + ui_child_transform + ");'><div class='card_idx' style='" + str_style_child_transform + arr_indo_disp_style[6] + "'>" + obj_check_param.module_card_idx + "</div></div>";
        }

        var str_module_style = obj_check_param.module_style + str_style_offset + str_style_transform;
        // 构建字串
        var str_lock_tip = "<div class='mc_mod_right_top' style='transform:scale(" + ui_child_transform + ");'><div class='mc_lock_icon icon-lock' style='" + str_style_child_transform + "'></div></div>";

        var str_show_name_html = get_show_name_html(obj_check_param.module_show_name, str_style_child_transform + arr_indo_disp_style[0]);
        var str_module_box_attr = "class='" + str_class_list + "' tabindex='-1' mod_id='" + obj_check_param.module_id + "' style='" + str_module_style + str_img_url + "' mod_wg='" + obj_check_param.width + "' mod_hg='" + obj_check_param.height + "' " + str_easy_mode + " " + obj_check_param.attr + " " + str_transform_mag_attr;
        var str_msg_box_html = "<div class='mod_msg_box' style='transform:scale(" + ui_child_transform + ");'>" + str_show_name_html + str_ctrlchip_html + "<div class='mod_size' style='" + str_style_child_transform + arr_indo_disp_style[3] + "'>" + str_size + "</div><div class='mod_pot' style='" + str_style_child_transform + arr_indo_disp_style[2] + "'>" + str_pot + "</div><div class='mod_list_idx' style='" + str_style_child_transform + arr_indo_disp_style[5] + "'>" + obj_check_param.module_list_idx + "</div></div>";
        var str_box_html = "<div id='" + str_mod_id + "' " + str_module_box_attr + " onmousedown='mc_mod_mousedown(event,this)'>";

        if (!b_istouch) {
            str_box_html = "<div id='" + str_mod_id + "' " + str_module_box_attr + " ontouchstart='mc_mod_mousedown(event,this)'>";
        }
        var str_html = str_box_html + str_msg_box_html + "<div class='mod_hub_box' style='transform:scale(" + ui_child_transform + ");'><div class='mod_hub_div' style='" + str_style_child_transform + arr_indo_disp_style[4] + "'>" + str_center_hub_val + "</div></div>" + str_card_index + str_lock_tip + "</div>";
        // 保存连线队列id
        var str_key = false;

        if ("?" !== str_center_hub_val) {
            if (b_create_grid) {
                str_key = str_center_hub_val;
            } else {
                str_key = obj_check_param.module_card_idx + ":" + str_center_hub_val;
            }
        } else {
            arr_default_module_id.push(str_mod_id);
        }

        if (str_key) {
            if (obj_module_line_id[str_key]) {
                obj_module_line_id[str_key].push(str_mod_id);
            } else {
                obj_module_line_id[str_key] = [str_mod_id];
            }
        }

        return { str_html: str_html, obj_module_line_id: obj_module_line_id };
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    添加模块字串
    * 参数:
    *    @param { Promise<String> } str_html 模块html
    *    @param { Promise<Object> } obj_module_line_id 当前连线对象
    *    @param { Promise<Boolean> } b_add_virtual 是否正在创建虚拟模组 可为空
    * 返回：
    *    @return { Promise<Boolean> }
    *     {obj_same_hub_queue:连线对象队列, arr_mod_selected:当前添加模块jq数组}
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2021.01.09
    *      内容 : 所有代码
    ************************************************************************************************/
    this.add_module_html = function (str_html, obj_module_line_id, b_add_virtual) {
        if ("[object String]" !== Object.prototype.toString.call(str_html) || 0 === str_html.length) {
            return false;
        }
        if ("[object Object]" !== Object.prototype.toString.call(obj_module_line_id)) {
            return false;
        }
        $(".mc_mod_box").prepend(str_html);
        // 字串添加渲染 初始化
        var obj_data = mc_init_construct_module(obj_module_line_id, arr_default_module_id, b_select_fn, b_add_virtual);

        // 未设置连线模块id
        arr_default_module_id = [];
        return obj_data;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    是否创建canvas格子
    * 参数:
    *    @param { Promise<Boolean> } b_create true创建
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  添加成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.8.18
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_create_grid = function (b_create) {
        if ("[object Boolean]" !== Object.prototype.toString.call(b_create)) {
            return false;
        }
        b_create_grid = b_create;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    嵌套框添加class类 控件父元素
    * 参数:
    *    @param { Promise<String> } str_css class类名
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  添加成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_box_add_css = function (str_css) {
        if ("[object String]" !== Object.prototype.toString.call(str_css) || 0 === str_css.length) {
            return false;
        }
        ary_box_class.push(str_css);
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    嵌套框移除clas类
    * 参数:
    *    @param { Promise<String> } str_css class类名
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  移除成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_box_del_css = function (str_css) {
        if ("[object String]" !== Object.prototype.toString.call(str_css) || 0 === str_css.length) {
            return false;
        }
        for (var idx_css = 1; idx_css < ary_box_class.length; idx_css++) {
            if (ary_box_class[idx_css] === str_css) {
                ary_box_class.splice(idx_css, 1);
                break;
            }
        }
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置默认创建最大格子宽度
    * 参数:
    *    @param { Promise<Number> } ui_max_w 格子最大宽度
    * 返回：
    *    @return { Promise<Boolean> }
    *     true 设置成功
    *     false 参数错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.01.10
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_max_grid = function (ui_max_w) {
        if ("[object Number]" !== Object.prototype.toString.call(ui_max_w) || isNaN(ui_max_w)) {
            return false;
        }
        ui_max_grid = ui_max_w;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置缩放-缩小 限制
    * 参数:
    *    @param { Promise<Number> } ui_min_w 格子最小宽度
    * 返回：
    *    @return { Promise<Boolean> }
    *     true 设置成功
    *     false 参数错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.01.10
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_min_scale = function (ui_min_w) {
        if ("[object Number]" !== Object.prototype.toString.call(ui_min_w) || isNaN(ui_min_w)) {
            return false;
        }
        ui_min_scale = ui_min_w;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    创建嵌套框标签
    * 参数:
    *    无
    * 返回：
    *    @return { Promise<String> }
    *     嵌套框标签
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.get_box_html = function () {
        var str_class_list = "";

        // 类数组转化为字符串
        for (var idx_class = 0; idx_class < ary_box_class.length; idx_class++) {
            str_class_list += ary_box_class[idx_class] + " ";
        }
        str_class_list = str_class_list.trim();
        ui_mod_box_scale = Math.floor(3 / ui_max_grid * 100);

        // 触发回调函数
        var str_val_chg_callback_attr = "";
        var str_attr_operate_mod_end = "";
        var str_bg_style = "";
        var str_box_transform = "transform:scale(" + ui_mod_box_scale / 100 + ");";
        var str_move_layer_html = "<div id='mc_move_layer' style='position: absolute; " + str_box_transform + "'><div id='mc_blk_move'></div></div>";
        // var ui_grid_w = 1;


        if ("function" === typeof this.on_val_chg) {
            str_val_chg_callback_attr = g_str_attr_lab_val_chg + "='" + mc_get_func_key(this.on_val_chg) + "'";
        }
        if ("function" === typeof this.operate_mod_end) {
            str_attr_operate_mod_end = g_str_attr_operate_mod_end + "='" + mc_get_func_key(this.operate_mod_end) + "'";
        }
        // 调用箱体ctrl+鼠标滚轮放大缩小
        mc_scope_zoom();
        if (b_create_grid) {
            str_bg_style = "background-image:url(" + create_repeat_img(ui_max_grid) + ")";
            // ui_grid_w = ui_max_grid;
            // 区分标识位置
            str_class_list += " " + "mc_box_tip_pnt";
        } else {
            str_bg_style = "background-color:#255388;";
            // str_class_list += " " + "mc_screen_tip_pnt";
            if (4 === ui_min_scale) {
                // 大屏最小缩放倍数
                ui_min_scale = 0.1;
                ui_box_scale_step = 0.1;
            }
        }
        // grid_w 当前格子宽度
        return str_move_layer_html + "<div id='mod_box_next' style='" + str_box_transform + "' class='" + str_class_list + "' tabindex='-1' mod_focus='true' create_grid=" + b_create_grid + " grid_w = " + ui_max_grid + " min_scale='" + ui_min_scale + "' " + str_val_chg_callback_attr + str_attr_operate_mod_end + " ><div id='mc_box_canvasbg' style='width:1000%;height:1000%;" + str_bg_style + "' onclick='mc_get_focus()'></div>";
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置模组的样式 宽
    * 参数:
    *    @param { Promise<Number> } ui_width canvas背景方格数
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_style_width = function (ui_width) {
        if ("[object Number]" !== Object.prototype.toString.call(ui_width) || isNaN(ui_width)) {
            return false;
        }
        // 当前背景格子宽度
        var ui_grid = document.getElementById("mod_box_next").getAttribute("grid_w");
        var b_add = true;

        uni_mod_wg = ui_width;
        for (var idx_style = 0; idx_style < ary_mod_style.length; idx_style++) {
            var arr_item_style = ary_mod_style[idx_style];

            if ("width" === arr_item_style[0]) {
                arr_item_style[1] = ui_grid * ui_width + "px";
                b_add = false;
                break;
            }
        }
        if (b_add) {
            ary_mod_style.push(["width", ui_grid * ui_width + "px"]);
        }
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置模组的样式 高
    * 参数:
    *    @param { Promise<Number> } ui_height canvas背景方格数
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_style_height = function (ui_height) {
        if ("[object Number]" !== Object.prototype.toString.call(ui_height) || isNaN(ui_height)) {
            return false;
        }
        // 当前背景格子宽度
        var ui_grid = document.getElementById("mod_box_next").getAttribute("grid_w");
        var b_add = true;

        for (var idx_style = 0; idx_style < ary_mod_style.length; idx_style++) {
            var arr_item_style = ary_mod_style[idx_style];

            if ("height" === arr_item_style[0]) {
                arr_item_style[1] = ui_grid * ui_height + "px";
                b_add = false;
                break;
            }
        }
        if (b_add) {
            ary_mod_style.push(["height", ui_grid * ui_height + "px"]);
        }
        uni_mod_hg = ui_height;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置模组的样式 左边距
    * 参数:
    *    @param { Promise<Number> } left canvas背景方格数
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_style_left = function (left) {
        if ("[object Number]" !== Object.prototype.toString.call(left) || isNaN(left)) {
            return false;
        }
        // 当前背景格子宽度
        var ui_grid = document.getElementById("mod_box_next").getAttribute("grid_w");
        var b_add = true;

        for (var idx_style = 0; idx_style < ary_mod_style.length; idx_style++) {
            var arr_item_style = ary_mod_style[idx_style];

            if ("left" === arr_item_style[0]) {
                arr_item_style[1] = ui_grid * left + "px";
                b_add = false;
                break;
            }
        }
        if (b_add) {
            ary_mod_style.push(["left", ui_grid * left + "px"]);
        }

        ui_pot_left = left;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置模组的样式 上边距
    * 参数:
    *    @param { Promise<Number> } top canvas背景方格数
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_style_top = function (top) {
        if ("[object Number]" !== Object.prototype.toString.call(top) || isNaN(top)) {
            return false;
        }
        // 当前背景格子宽度
        var ui_grid = document.getElementById("mod_box_next").getAttribute("grid_w");
        var b_add = true;

        for (var idx_style = 0; idx_style < ary_mod_style.length; idx_style++) {
            var arr_item_style = ary_mod_style[idx_style];

            if ("top" === arr_item_style[0]) {
                arr_item_style[1] = ui_grid * top + "px";
                b_add = false;
                break;
            }
        }
        if (b_add) {
            ary_mod_style.push(["top", ui_grid * top + "px"]);
        }

        ui_pot_top = top;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    添加模组的class类
    * 参数:
    *    @param { Promise<String> } str_css class类名
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  添加成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_add_css = function (str_css) {
        if ("[object String]" !== Object.prototype.toString.call(str_css) || 0 === str_css.length) {
            return false;
        }
        if (1 < ary_mod_class.length) {
            for (var idx_class = 0; idx_class < ary_mod_class.length; idx_class++) {
                if (str_css !== ary_mod_class[idx_class]) {
                    ary_mod_class.push(str_css);
                }
            }
        } else {
            ary_mod_class.push(str_css);
        }
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    移除模组的class类
    * 参数:
    *    @param { Promise<String> } str_css class类名
    * 返回：
    *    @return { Promise<Boolean> }
    *     true  移除成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.12.03
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_del_css = function (str_css) {
        if ("[object String]" !== Object.prototype.toString.call(str_css) || 0 === str_css.length) {
            return false;
        }
        for (var idx_css = 1; idx_css < ary_mod_class.length; idx_css++) {
            if (ary_mod_class[idx_css] === str_css) {
                ary_mod_class.splice(idx_css, 1);
                break;
            }
        }
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置模组名称
    * 参数:
    *    @param { Promise<String> } str_item_id 模组名称
    * 返回：
    *   @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.01.16
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_id = function (str_item_id) {
        if ("[object String]" !== Object.prototype.toString.call(str_item_id) || 0 === str_item_id.length) {
            return false;
        }
        str_mod_item_id = str_item_id;

        return true;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    设置模块显示名称
     * 参数:
     *    @param { Promise<String> } str_name 模块显示的名称; 类名为 mod_show_name 块显示的值
     * 返回:
     *    @returns { Promise<Boolean> } true === 设置成功 || false === 失败
     * 例子:
     *    NA
     * 备注:
     *    NA
     * 修改:
     *    1. 类型 : 创建
     *       作者 : 巫昭雯
     *       时间 : 2020-12-24
     *       内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_show_name = function (str_name) {
        if ("[object String]" !== Object.prototype.toString.call(str_name) || 0 === str_name.length) {
            return false;
        }

        str_show_name = str_name;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置箱体芯片信息
    * 参数:
    *    @param { Promise<String> } str_name 芯片名
    * 返回：
    *   @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.9.4
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_chip_name = function (str_name) {
        if ("[object String]" !== Object.prototype.toString.call(str_name) || 0 === str_name.length) {
            return false;
        }
        str_chip_name = str_name;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置模组中心小圆的值
    * 参数:
    *    @param { Promise<String> } str_val 值
    * 返回：
    *   @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2019.01.19
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_mod_hub_val = function (str_val) {
        if ("[object String]" !== Object.prototype.toString.call(str_val) || 0 === str_val.length) {
            return false;
        }
        str_mod_center_val = str_val;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置模组变换参数 -创建变换模组时
    * 参数:
    *    @param { Promise<Array> } arr_transform 数组每项需为字符串
    * 备注:
    *    参数 ["X缩放","Y缩放","旋转角度","镜像类型"]
    * 返回：
    *   @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.10.20
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_transform_param = function (arr_transform) {
        if ("[object Array]" !== Object.prototype.toString.call(arr_transform)) {
            return false;
        }
        var str_transform = arr_transform.join();

        if ("1.0,1.0,0,0" === str_transform || "1,1,0,0" === str_transform) {
            return false;
        }
        ary_transform = arr_transform;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    是否开启描点
    * 参数:
    *    @param { Promise<Number> } ui_point 2 关闭描点
    * 返回：
    *   @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.10.27
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_tracing_point = function (ui_point) {
        if ("[object Number]" !== Object.prototype.toString.call(ui_point) || isNaN(ui_point)) {
            return false;
        }
        ui_tracing_point = ui_point;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置卡下标 card_idx
    * 参数:
    *    @param { Promise<String> } str_idx
    * 返回：
    *   @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.12.16
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_card_idx = function (str_idx) {
        if ("[object String]" !== Object.prototype.toString.call(str_idx)) {
            return false;
        }
        str_card_idx = str_idx;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    设置在连线队列中下标 list_idx
    * 参数:
    *    @param { Promise<String> } str_idx
    * 返回：
    *   @return { Promise<Boolean> }
    *     true  设置成功
    *     false 参数类型错误
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.12.16
    *      内容 : 所有代码
    ************************************************************************************************/
    this.set_list_idx = function (str_idx) {
        if ("[object String]" !== Object.prototype.toString.call(str_idx)) {
            return false;
        }
        str_list_idx = str_idx;
        return true;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    添加模块字串
    * 参数:
    *     @param { Promise<String> } str_id 撤销删除时传入 创建模块id
    *     @param { Promise<Object> } obj_module_line_id 连线对象
    * 返回：
    *   @return { Promise<Object> }
    *   {str_html:模块字串，obj_module_line_id:当前连线id}
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2021.01.18
    *      内容 : 所有代码
    ************************************************************************************************/
    this.get_mod_html = function (str_id, obj_module_line_id) {
        if ("[object Object]" !== Object.prototype.toString.call(obj_module_line_id)) {
            return false;
        }
        var str_mod_id = str_id || "mod" + mc_get_id();
        var str_class_list = "";
        var str_style_list = "";

        // class list
        for (var idx_class = 0; idx_class < ary_mod_class.length; idx_class++) {
            str_class_list += ary_mod_class[idx_class] + " ";
        }

        str_class_list = str_class_list.trim();
        if ("?" === str_mod_center_val) {
            // 添加未设置port/jx标识
            str_class_list += " unset_module";
        }

        // style list
        if (0 !== ary_mod_style.length) {
            for (var idx_style = 0; idx_style < ary_mod_style.length; idx_style++) {
                str_style_list += ary_mod_style[idx_style][0] + ":" + ary_mod_style[idx_style][1] + ";";
            }
            str_style_list = str_style_list.trim();
        }
        var obj_params = {
            width: uni_mod_wg,
            height: uni_mod_hg,
            left: ui_pot_left,
            top: ui_pot_top,
            module_class: str_class_list,
            module_style: str_style_list,
            center_hub_val: str_mod_center_val,
            module_id: str_mod_item_id,
            module_list_idx: str_list_idx,
            module_card_idx: str_card_idx,
            transform_msg: ary_transform,
            ctrlchip_name: str_chip_name,
            module_show_name: str_show_name,
            attr: ""
        };

        var arr_msg = this.get_module_html_str(obj_params, obj_module_line_id, str_mod_id);

        // 清空模组参数
        ary_mod_style = [];
        ary_mod_class = ["mc_mod"];
        str_mod_item_id = "";
        str_show_name = "";
        str_mod_center_val = "?";
        str_chip_name = "";
        str_card_idx = "";
        str_list_idx = "?";
        ui_tracing_point = 1;
        // {str_html:模块字串，obj_module_line_id:当前连线id}
        return arr_msg;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    获取缩放参数
    * 参数:
    *    无
    * 返回：
    *   @return { Promise<Object> }
    *     缩放参数
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2021.02.24
    *      内容 : 所有代码
    ************************************************************************************************/
    this.get_zoom_params = function () {
        var obj_param = {
            ui_min: ui_min_scale,
            ui_max: 100,
            ui_step: ui_box_scale_step,
            ui_val: ui_mod_box_scale
        };

        return obj_param;
    };

    /************************************************************************************************
    * 类型:
    *    函数
    * 功能:
    *    判断模块是否需要创建canvas bg, 是获取对应创建canvas bg信息对象
    * 参数:
    *    @param { Promise<String> } str_grid 当前格子宽度字串
    *    @param { Promise<String> } str_mod_name mod_name 可为空
    * 返回：
    *   @return { Promise<Boolean> }
    *     false 参数错误
    *     {select_img_tip: select_img_tip模块canvasbg字串,str_img_url: 未选中canvasbg字串}
    * 修改:
    *   1. 类型 : 创建
    *      作者 : 陈小荟
    *      时间 : 2020.01.09
    *      内容 : 所有代码
    ************************************************************************************************/
    function mc_construct_moduele_canvas_bg(str_grid, str_mod_name) {
        if ("string" !== typeof str_grid || 0 === str_grid.length) {
            return false;
        }
        if (b_create_grid && 1 === ui_tracing_point) {
            var str_img_url = "";
            var str_select_bg = "";
            var b_create_url = true;
            var s_mod_name = 0 === str_mod_item_id.length ? str_mod_name : str_mod_item_id;
            // 判断是否之前创建过背景
            var obj_canvasbg = mc_judge_create_canvasbg(s_mod_name, str_grid);


            if ("[object Object]" === Object.prototype.toString.call(obj_canvasbg)) {
                str_img_url = obj_canvasbg.img_url;
                str_select_bg = obj_canvasbg.select_url;
                b_create_url = false;
            }
            // for (var idx = 0; idx < arr_get_img_url.length; idx++) {
            //     var obj_item = arr_get_img_url[idx];

            //     if (obj_item[s_mod_name] && str_grid === obj_item.grid) {
            //         str_img_url = obj_item.img_url;
            //         str_select_bg = obj_item.select_url;
            //         b_create_url = false;
            //         break;
            //     }
            // }

            if (b_create_url) {
                var obj_url = {};
                // 获取模组对应亮点格子数组
                // eslint-disable-next-line no-undef
                var ary_pix = mc_layout_get_mod_dot_location(s_mod_name, ARY_MOD_DATA);

                var ui_width = uni_mod_wg * str_grid;
                var ui_height = uni_mod_hg * str_grid;
                var arr_bgstr = set_mod_bgimg(ui_width, ui_height, ary_pix);

                str_img_url = arr_bgstr[0];
                str_select_bg = arr_bgstr[1];

                obj_url[s_mod_name] = ary_pix;
                obj_url.grid = str_grid;
                obj_url.img_url = str_img_url;
                obj_url.select_url = str_select_bg;
                arr_get_img_url.push(obj_url);
            }
            // save msg canvasbg
            // obj_msg.select_tip = str_select_bg;
            // obj_msg.no_select = str_img_url;

            return { select_tip: str_select_bg, no_select: str_img_url };
        }
        return false;
    }
}

/***************************HTML字串添加 参数效验及初始化**********************************************/
/************************************************************************************************
* 类型:
*    函数
* 功能:
*    效验创建模块字串参数
* 参数:
*    @param { Promise<Object> } obj_param 创建箱体字串参数
*    @param { Promise<Number> } ui_grid 格子宽度
* 返回：
*   @return { Promise<Boolean> }
*     obj_param 参数错误
*     obj_check_param 效验后参数对象
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.01.09
*      内容 : 所有代码
************************************************************************************************/
function mc_check_construct_module_params(obj_param, ui_grid) {
    if ("[object Object]" !== Object.prototype.toString.call(obj_param) || "[object Number]" !== Object.prototype.toString.call(ui_grid)) {
        return obj_param;
    }
    var str_module_class = "mc_mod";
    var arr_mod_class = obj_param.module_class;
    var arr_mod_style = obj_param.module_style;
    var str_center_hub = obj_param.center_hub_val;
    var str_list_idx = obj_param.module_list_idx;
    var str_card_idx = obj_param.module_card_idx;

    var obj_check_param = {
        width: 1,
        height: 1,
        left: 0,
        top: 0,
        module_class: "",
        module_style: "",
        center_hub_val: "?",
        module_id: obj_param.module_id || "",
        module_list_idx: "",
        module_card_idx: "",
        transform_msg: [],
        ctrlchip_name: "",
        module_show_name: "",
        attr: ""
    };

    // basics param----
    var obj_basics_resics = mc_check_basics_param(obj_param, obj_check_param);

    obj_check_param = obj_basics_resics;

    // center hub val---
    if (str_center_hub && 0 !== str_center_hub.length) {
        obj_check_param.center_hub_val = str_center_hub;
    }

    if ("?" === obj_check_param.center_hub_val) {
        // 添加未设置port/jx标识
        str_module_class += " unset_module";
    }


    // class str---
    if (arr_mod_class && 0 !== arr_mod_class.length) {
        for (var i = 0; i < arr_mod_class.length; i++) {
            var str_class = arr_mod_class[i];

            if (str_class && 0 !== str_class.length) {
                str_module_class += " " + str_class.trim();
            }
        }
    }
    obj_check_param.module_class = str_module_class;

    // style str---
    // basics style
    var str_style_list = "width:" + obj_check_param.width * ui_grid + "px;height:" + obj_check_param.height * ui_grid + "px;";

    // extra style
    if (arr_mod_style && 0 !== arr_mod_style.length) {
        for (var idx_style = 0; idx_style < arr_mod_style.length; idx_style++) {
            str_style_list += arr_mod_style[idx_style][0] + ":" + arr_mod_style[idx_style][1] + ";";
        }
        str_style_list = str_style_list.trim();
    }
    obj_check_param.module_style = str_style_list;

    // list idx---
    if (str_list_idx && 0 !== str_list_idx.length) {
        obj_check_param.module_list_idx = str_list_idx;
    }

    // card idx---
    if (str_card_idx && 0 !== str_card_idx.length) {
        obj_check_param.module_card_idx = str_card_idx;
    }

    return obj_check_param;

    // 拆分复杂度
    function mc_check_basics_param(o_param, o_check_param) {
        var str_chip_name = obj_param.ctrlchip_name;
        var str_show_name = obj_param.module_show_name;
        var str_attr = obj_param.attr;
        var arr_transform = obj_param.transform_msg;

        if (o_param.width) {
            o_check_param.width = Number(o_param.width);
        }
        if (o_param.height) {
            o_check_param.height = Number(o_param.height);
        }
        if (o_param.left) {
            o_check_param.left = Number(o_param.left);
        }
        if (o_param.top) {
            o_check_param.top = Number(o_param.top);
        }
        // ctrlchip name
        if (str_chip_name && 0 !== str_chip_name.length) {
            o_check_param.ctrlchip_name = str_chip_name;
        }
        // use module name
        if (str_show_name && 0 !== str_show_name.length) {
            o_check_param.module_show_name = str_show_name;
        }
        // attr
        if (str_attr && 0 !== str_attr.length) {
            o_check_param.attr = str_attr;
        }
        // transform msg---
        if (arr_transform && 4 <= arr_transform.length) {
            if ("1.0" !== arr_transform[0] || "1.0" !== arr_transform[1] || "0" !== arr_transform[2] || "0" !== arr_transform[3] || "0,0,0,0" !== arr_transform[4]) {
                o_check_param.transform_msg = arr_transform;
            }
        }
        return o_check_param;
    }
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    字串添加渲染 初始化设置
*       1. 获取连线队列数据
*       2. 存储信息
*       3. 变换模块初始化变换
*       4. 模块事件初始化
*       5. 创建虚拟模组时 隐藏子元素
* 参数:
*    @param { Promise<Object> } obj_line_id 连线队列id 部分可能为jq元素(之前添加)
*    @param { Promise<Array> } arr_default_module_id 未设置连线id数组
*    @param { Promise<Boolean> } b_select_fn 是否调用框选标识
*    @param { Promise<Boolean> } b_add_virtual 是否在创建虚拟模组 可为空
* 返回：
*   @return { Promise<Boolean> }
*     false 参数错误
*     obj_same_hub_queue 连线对象队列 arr_mod_selected当前添加模块jq数组
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.01.09
*      内容 : 所有代码
************************************************************************************************/
function mc_init_construct_module(obj_line_id, arr_default_module_id, b_select_fn, b_add_virtual) {
    if ("[object Object]" !== Object.prototype.toString.call(obj_line_id)) {
        return false;
    }
    if ("[object Array]" !== Object.prototype.toString.call(arr_default_module_id)) {
        return false;
    }
    var arr_key = Object.keys(obj_line_id);
    var arr_select = [];

    for (var i = 0; i < arr_key.length; i++) {
        var str_key = arr_key[i];
        var arr_id = obj_line_id[str_key];

        for (var j = 0; j < arr_id.length; j++) {
            // string = id, object = jqobject
            var item = arr_id[j];

            // 转换对象 初始化设置
            if ("string" === typeof item && 0 !== item.length) {
                var obj_jq = $("#" + arr_id[j]);

                if (obj_jq && 0 !== obj_jq.length) {
                    obj_line_id[str_key][j] = obj_jq;
                    mc_init_construct_module_set(obj_jq, item, b_select_fn, b_add_virtual);
                    arr_select.push(obj_jq);
                }
            }
        }
    }

    // 初始化 未设置连线模块
    for (var z = 0; z < arr_default_module_id.length; z++) {
        var str_id = arr_default_module_id[z];
        var obj_default_jq = $("#" + arr_default_module_id[z]);

        if (obj_default_jq && 0 !== obj_default_jq.length) {
            mc_init_construct_module_set(obj_default_jq, str_id, b_select_fn, b_add_virtual);
            arr_select.push(obj_default_jq);
        }
    }
    return { obj_same_hub_queue: obj_line_id, arr_mod_selected: arr_select };
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    字串添加渲染 初始化
* 参数:
*    @param { Promise<Object> } obj_target_jq 当前设置jq对象
*    @param { Promise<String> } str_id 当前设置对象id
*    @param { Promise<Boolean> } b_select_fn 是否调用框选标识
*    @param { Promise<Boolean> } b_add_virtual 是否在创建虚拟模组 可为空
* 返回：
*   @return { Promise<Boolean> }
*     false 参数错误
*     true 初始化成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2021.01.09
*      内容 : 所有代码
************************************************************************************************/
function mc_init_construct_module_set(obj_target_jq, str_id, b_select_fn, b_add_virtual) {
    if ("[object Object]" !== Object.prototype.toString.call(obj_target_jq)) {
        return false;
    }
    if ("[object String]" !== Object.prototype.toString.call(str_id)) {
        return false;
    }
    if ("[object Boolean]" !== Object.prototype.toString.call(b_select_fn)) {
        return false;
    }

    // 存储信息
    mc_save_module_msg(obj_target_jq);
    // 初始化框选
    if (b_select_fn) {
        mod_select(".mc_mod_box");
        ui_box_center_x = $(".mc_mod_box").width() / 2;
        ui_box_center_y = $(".mc_mod_box").height() / 2;
        b_select_fn = false;
    }
    // 创建虚拟模组将子元素隐藏,除锁定标识
    if (b_add_virtual) {
        var child_list = obj_target_jq.children();

        for (var i = 0; i < child_list.length - 1; i++) {
            child_list.eq(i).css("display", "none");
        }
    }
    return true;
}

/***************************模块替换、删除、排列**********************************************************/
/************************************************************************************************
* 类型:
*    函数
* 功能:
*    替换框选模组
* 参数:
*    @param { Promise<Number> } ui_width 新模组宽格子数
*    @param { Promise<Number> } ui_height 新模组高格子数
*    @param { Promise<String> } str_id 模组id/箱体id
*    @param { Promise<String> } ctrlchip_name 箱体使用芯片信息 可为空
* 返回：
*   @return { Promise<Boolean> }
*     true  替换成功
*     false 参数错误/当前无框选项
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.01.08
*      内容 : 所有代码
************************************************************************************************/
function mc_set_replace_mod(ui_width, ui_height, str_id, ctrlchip_name) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_width) || isNaN(ui_width)) {
        return false;
    }
    if ("[object Number]" !== Object.prototype.toString.call(ui_height) || isNaN(ui_height)) {
        return false;
    }
    if ("[object String]" !== Object.prototype.toString.call(str_id)) {
        return false;
    }
    var ui_grid = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));

    var i_width = ui_grid * ui_width;
    var i_height = ui_grid * ui_height;
    var str_img_url = "";
    var str_no_select = "";
    var i_del_num = 0;

    if (b_create_grid) {
        var obj_bg = mc_judge_create_canvasbg(str_id, String(ui_grid));

        if ("[object Object]" === Object.prototype.toString.call(obj_bg)) {
            // 存在
            str_no_select = obj_bg.img_url;
            str_img_url = obj_bg.select_url;
        } else {
            // 不存在 创建存储
            var obj_url = {};
            // eslint-disable-next-line no-undef
            var ary_pix = mc_layout_get_mod_dot_location(str_id, ARY_MOD_DATA);

            str_no_select = set_mod_bgimg(i_width, i_height, ary_pix)[0];
            str_img_url = set_mod_bgimg(i_width, i_height, ary_pix)[1];
            obj_url[str_id] = ary_pix;
            obj_url.grid = String(ui_grid);
            obj_url.img_url = str_no_select;
            obj_url.select_url = str_img_url;
            arr_get_img_url.push(obj_url);
        }
    }

    for (var idx_mod = 0; idx_mod < arr_select_mod.length; idx_mod++) {
        var o_mod = arr_select_mod[idx_mod];

        if (!b_create_grid && "string" === typeof ctrlchip_name) {
            mc_get_appoint_obj(o_mod, "chip_name").innerText = ctrlchip_name;
        }
        o_mod.css({ "width": i_width + "px", "height": i_height + "px" }).attr({ "mod_id": str_id, "mod_wg": ui_width, "mod_hg": ui_height });
        mc_get_appoint_obj(o_mod, "mod_size", true).text(ui_width + "X" + ui_height);
        if ("" !== str_img_url) {
            o_mod.css("background-image", "url(" + str_img_url + ")");
        }
        // 更新模块信息
        mc_update_module_msg(o_mod[0].id, false, ui_width + "X" + ui_height, str_img_url, str_no_select);
        i_del_num += 1;
    }

    if (0 === i_del_num) {
        return false;
    }
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    移除框选模组
* 参数:
*    无
* 返回：
*   @return { Promise<Boolean> }
*     true  移除成功
*     false 当前无框选项
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.01.08
*      内容 : 所有代码
************************************************************************************************/
function mc_set_mod_del() {
    var ui_cnt = arr_select_mod.length;

    if (0 === ui_cnt) {
        return false;
    }
    for (var idx = 0; idx < ui_cnt; idx++) {
        var obj_jq = arr_select_mod[idx];

        if ("[object Object]" === Object.prototype.toString.call(obj_jq)) {
            obj_jq.remove();
        }
    }
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    水平排列框选模组
* 参数:
*    @param { Promise<Number> } ui_direction 排列方向 任意上对齐排列 2下对齐排列 不可为空
* 返回：
*   @return { Promise<Boolean> }
*     true  排列成功
*     false 参数错误/当前无框选项
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.01.14
*      内容 : 所有代码
************************************************************************************************/
function mc_set_level_mod(ui_direction) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_direction) || isNaN(ui_direction)) {
        return false;
    }
    if (2 > arr_select_mod.length) {
        return false;
    }
    // 选中元素宽
    var arr_mod_w = [0];
    // 高差距
    var arr_mod_h = [];
    // 递增宽
    var ui_temp = 0;
    var ui_left_move = 0;
    var ui_top_move = 0;
    // 当前背景格子宽度
    var i_grid_width = document.getElementById("mod_box_next").getAttribute("grid_w");
    var operate_param = new mc_layout_operate_format_data();

    i_grid_width = parseInt(i_grid_width, 10);
    operate_param.obj_list = mc_transform_id_data(arr_select_mod);
    // operate_param.obj_module_size_txt.undo = mc_get_module_size_msg();
    for (var idx_mod = 0, len = arr_select_mod.length; idx_mod < len; idx_mod++) {
        var o_item = arr_select_mod[idx_mod][0];
        var arr_size = mc_get_optsize_msg(o_item, true);

        arr_mod_w.push(arr_size[0] + ui_temp);
        ui_temp += arr_size[0];
        ui_left_move = ui_left + arr_mod_w[idx_mod];
        o_item.style.left = ui_left_move + "px";

        var ui_x = parseInt(ui_left_move / i_grid_width, 10);
        var ui_y = false;

        if (2 === ui_direction) {
            var ui_first_h = mc_get_optsize_msg(arr_select_mod[0][0], true)[1];
            var ui_item_h = arr_size[1];
            var ui_gap_h = ui_first_h - ui_item_h;

            arr_mod_h.push(ui_gap_h);
            ui_top_move = ui_top + arr_mod_h[idx_mod];
            o_item.style.top = ui_top_move + "px";
            ui_y = parseInt(ui_top_move / i_grid_width, 10);
        } else {
            o_item.style.top = ui_top + "px";
            ui_y = parseInt(ui_top / i_grid_width, 10);
        }
        update_mod_pot(o_item, ui_x, ui_y, false, operate_param);
    }
    return operate_param;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    垂直排列框选模组
* 参数:
*    @param { Promise<Number> } ui_direction 排列方向 任意左对齐排列 2右对齐排列 不可为空
* 返回：
*   @return { Promise<Boolean> }
*     true  排列成功
*     false 参数错误/当前无框选项
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.01.14
*      内容 : 所有代码
************************************************************************************************/
function mc_set_vertical_mod(ui_direction) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_direction) || isNaN(ui_direction)) {
        return false;
    }
    if (2 > arr_select_mod.length) {
        return false;
    }
    // mod元素高
    var arr_mod_h = [0];
    // 宽差距
    var arr_mod_w = [];
    // 递增高
    var ui_temp = 0;
    // 当前背景格子宽度
    var i_grid_width = document.getElementById("mod_box_next").getAttribute("grid_w");
    var operate_param = new mc_layout_operate_format_data();

    i_grid_width = parseInt(i_grid_width, 10);
    operate_param.obj_list = mc_transform_id_data(arr_select_mod);

    for (var idx_mod = 0, len = arr_select_mod.length; idx_mod < len; idx_mod++) {
        var o_item = arr_select_mod[idx_mod][0];
        var ui_x = parseInt(ui_left / i_grid_width, 10);
        var arr_size = mc_get_optsize_msg(o_item, true);

        arr_mod_h.push(arr_size[1] + ui_temp);
        ui_temp += arr_size[1];
        o_item.style.left = ui_left + "px";
        if (2 === ui_direction) {
            var ui_first_w = mc_get_optsize_msg(arr_select_mod[0][0], true)[0];
            var ui_item_w = arr_size[0];
            var ui_gap_w = ui_first_w - ui_item_w;

            arr_mod_w.push(ui_gap_w);
            o_item.style.left = ui_left + arr_mod_w[idx_mod];
            ui_x = parseInt((ui_left + arr_mod_w[idx_mod]) / i_grid_width, 10);
        }
        o_item.style.top = ui_top + arr_mod_h[idx_mod] + "px";
        var ui_y = parseInt((ui_top + arr_mod_h[idx_mod]) / i_grid_width, 10);

        update_mod_pot(o_item, ui_x, ui_y, false, operate_param);
    }
    return operate_param;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    对齐框选模组 / 层叠框选模组
* 参数:
*    @param { Promise<String> } str_type 对齐类型 ("level")水平 (任意字符串)为垂直 不可为空
*    @param { Promise<Number> } ui_direction 对齐方向 (任意)上/左对齐 (2)下/右对齐 不可为空
*    @param { Promise<Number> } ui_tiled_grid 层叠偏移格子数 可为而空 为空则对齐 为数字则层叠
* 注意：当调用作为层叠函数时，参数2不可为(2)
* 举例层叠传参：
*    水平偏移层叠50格 -> ("level", 0, 50)
*    垂直偏移层叠10格 -> ("2", 0, 10)
* 返回：
*   @return { Promise<Boolean> }
*     true  对齐成功
*     false 参数错误/当前无框选项
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.04.14
*      内容 : 所有代码
************************************************************************************************/
function mc_set_level_align_mod(str_type, ui_direction, ui_tiled_grid) {
    if ("[object String]" !== Object.prototype.toString.call(str_type) || 0 === str_type.length) {
        return false;
    }
    if ("[object Number]" !== Object.prototype.toString.call(ui_direction) || isNaN(ui_direction)) {
        return false;
    }
    if (2 > arr_select_mod.length) {
        return false;
    }
    // 最大最小对齐标线
    var ui_max = -Math.pow(2, 32);
    var ui_min = Math.pow(2, 32);
    // 对照项
    var o_item_max = "";
    var arr_mod = arr_select_mod;

    // 递增偏移
    var ui_temp_l = 0;
    var ui_temp_t = 0;
    // 基准元素top，left
    var ui_basics_l = Math.pow(2, 32);
    var ui_basics_t = Math.pow(2, 32);
    // 当前背景格子宽度
    var i_grid_width = document.getElementById("mod_box_next").getAttribute("grid_w");
    var operate_param = new mc_layout_operate_format_data();

    i_grid_width = parseInt(i_grid_width, 10);
    if (obj_item_checkbox_easy_mode.get_dom_val()) {
        mc_easy_mode_align_tile(arr_select_mod, str_type, ui_direction, ui_tiled_grid);
        return true;
    }

    // 排列模组位置
    arr_mod = set_arr_select_mod(true);
    // 构造数组 每项为模块与其外接矩形偏移对象
    var ary_mod = [];

    operate_param.obj_list = mc_transform_id_data(arr_mod);
    // 确定对照位置及对照项
    for (var idx_mod_pot = 0, len_pot = arr_mod.length; idx_mod_pot < len_pot; idx_mod_pot++) {
        var o_item_pot = arr_mod[idx_mod_pot][0];
        var ui_item_gap = "";
        var arr_pot = mc_get_optsize_msg(o_item_pot, false, true);
        var ui_offset_t = arr_pot[1];
        var ui_offset_l = arr_pot[0];
        var obj_msg = new modblk();

        obj_msg.obj = o_item_pot;
        obj_msg.ui_x = arr_pot[2];
        obj_msg.ui_y = arr_pot[3];
        ary_mod.push(obj_msg);
        if ("level" === str_type) {
            ui_item_gap = ui_offset_t;
        } else {
            ui_item_gap = ui_offset_l;
        }
        if (ui_max < ui_item_gap) {
            ui_max = ui_item_gap;
            o_item_max = o_item_pot;
        }
        if (ui_min > ui_item_gap) {
            ui_min = ui_item_gap;
        }
        // 偏移基准元素位置
        if (ui_basics_l > ui_offset_l) {
            ui_basics_l = ui_offset_l;
        }
        if (ui_basics_t > ui_offset_t) {
            ui_basics_t = ui_offset_t;
        }
    }

    var arr_max_size = mc_get_optsize_msg(o_item_max, true);

    // 修改位置
    for (var idx_mod = 0, len = ary_mod.length; idx_mod < len; idx_mod++) {
        var obj_item_msg = ary_mod[idx_mod];
        var o_item = obj_item_msg.obj;
        // 与外接矩形偏移差
        var ui_boundx = obj_item_msg.ui_x;
        var ui_boundy = obj_item_msg.ui_y;
        var ui_gap = 0;
        var ui_x = false;
        var ui_y = false;
        var arr_size = mc_get_optsize_msg(o_item, true);
        var ui_offset = 0;

        if ("level" === str_type) {
            ui_gap = arr_max_size[1] - arr_size[1];
            if (2 === ui_direction) {
                ui_offset = ui_max + ui_gap + ui_boundy;
                o_item.style.top = ui_offset + "px";
                ui_y = parseInt(ui_offset / i_grid_width, 10);
            } else {
                // 水平偏移
                if ("number" === typeof ui_tiled_grid) {
                    ui_offset = ui_basics_l + ui_temp_l + ui_boundx;

                    o_item.style.left = ui_offset + "px";
                    ui_x = parseInt(ui_offset / i_grid_width, 10);
                    ui_temp_l += ui_tiled_grid * i_grid_width;
                    o_item.style.zIndex = idx_mod;
                    o_item.setAttribute("addzindex", idx_mod);
                }
                ui_offset = ui_min + ui_boundy;
                o_item.style.top = ui_offset + "px";
                ui_y = parseInt(ui_offset / i_grid_width, 10);
            }
        } else {
            ui_gap = arr_max_size[0] - arr_size[0];
            if (2 === ui_direction) {
                ui_offset = ui_max + ui_gap + ui_boundx;
                o_item.style.left = ui_offset + "px";
                ui_x = parseInt(ui_offset / i_grid_width, 10);
            } else {
                // 垂直偏移
                if ("number" === typeof ui_tiled_grid) {
                    ui_offset = ui_basics_t + ui_temp_t - ui_boundy;

                    o_item.style.top = ui_offset + "px";
                    ui_y = parseInt(ui_offset / i_grid_width, 10);
                    ui_temp_t += ui_tiled_grid * i_grid_width;
                    o_item.style.zIndex = idx_mod;
                    o_item.setAttribute("addzindex", idx_mod);
                }
                ui_offset = ui_min + ui_boundx;
                o_item.style.left = ui_offset + "px";
                ui_x = parseInt(ui_offset / i_grid_width, 10);
            }
        }

        update_mod_pot(o_item, ui_x, ui_y, true, operate_param);
    }
    return operate_param;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    格式定义
 * 参数:
 *     无
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.5.27
 *      内容 : 所有代码
 ************************************************************************************************/
function modblk() {
    /* eslint-disable no-unused-vars */
    var ui_x = 0;
    var ui_y = 0;
    // 与外接矩形偏差
    var ui_lc = 0;
    var ui_tx = 0;
    var obj = null;
}

/***************************canvas背景相关函数****************************************************/
/************************************************************************************************
* 类型:
*    函数
* 功能:
*    判断是否存在当前需要创建bg 存在返回
* 参数:
*    @param { Promise<String> } str_mod_item_id 模块mod_name
*    @param { Promise<String> } str_grid 画布格子宽度
* 返回：
*   @return { Promise<Object> }
*     null 参数错误/不存在此bg
*     {select_url:选中canvasbg字串, img_url: 未选中canvasbg字串}
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.01.09
*      内容 : 所有代码
************************************************************************************************/
function mc_judge_create_canvasbg(str_mod_item_id, str_grid) {
    if ("[object String]" !== Object.prototype.toString.call(str_mod_item_id) || 0 === str_mod_item_id.length) {
        return null;
    }
    if ("[object String]" !== Object.prototype.toString.call(str_grid) || 0 === str_grid.length) {
        return null;
    }
    for (var idx = 0; idx < arr_get_img_url.length; idx++) {
        var obj_item = arr_get_img_url[idx];

        if (obj_item[str_mod_item_id] && str_grid === obj_item.grid) {
            return { img_url: obj_item.img_url, select_url: obj_item.select_url };
        }
    }
    return null;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    创建修改嵌套框canvas背景图
 * 参数:
 *    @param { Promise<Number> } ui_size 背景格子宽度
 * 返回：
 *    @return { Promise<String> }
 *     "" 参数有误
 *     url 背景字串
 * 备注：
 *    如果性能过低可考虑优化画法 只画虚点/实点，填充背景直接画网格线
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.03.26
 *      内容 : 所有代码
 ************************************************************************************************/
function create_repeat_img(ui_size) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_size) || isNaN(ui_size)) {
        return "";
    }
    if (2 > ui_size) {
        ui_size = 2;
    }

    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");

    // set size
    canvas.width = ui_size;
    canvas.height = ui_size;

    // draw background
    ctx.fillStyle = "rgba(37,83,136,1)";
    // ctx.fillStyle = "#fff";
    ctx.fillRect(0, 0, ui_size, ui_size);

    ctx.beginPath();
    ctx.moveTo(ui_size, 0);
    ctx.lineTo(ui_size, ui_size);
    ctx.lineTo(0, ui_size);
    ctx.strokeStyle = "#000000";
    // ctx.strokeStyle = "#aaa";
    ctx.lineWidth = 3;
    ctx.stroke();

    return canvas.toDataURL();
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    快速布局画布大小适应
* 参数:
*    @param { Promise<Number> } ui_w 格子数
*    @param { Promise<Number> } ui_h
* 返回：
*    @return { Promise<Boolean> }
*     false 参数错误
*     true 设置成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.9.14
*      内容 : 所有代码
************************************************************************************************/
function mc_adapt_canvasbg_size(ui_w, ui_h) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_w) || isNaN(ui_w)) {
        return false;
    }
    if ("[object Number]" !== Object.prototype.toString.call(ui_h) || isNaN(ui_h)) {
        return false;
    }
    var ui_grid = Number($("#mod_box_next").attr("grid_w"));
    var obj_bg = $("#mc_box_canvasbg");
    var b_set_canvas = false;
    var ui_set_canvas = 0;

    if ("[object Function]" === Object.prototype.toString.call(adapt_canvas_size)) {
        b_set_canvas = true;
    }

    if (0 !== obj_bg.length) {
        ui_w *= ui_grid;
        ui_h *= ui_grid;
        var ui_ow = obj_bg.width();
        var ui_oh = obj_bg.height();

        if (ui_ow < ui_w) {
            var ui_show_w = ui_canvasbg_size_w * ui_grid;

            ui_set_canvas = ui_w + 100 * ui_grid;
            if (ui_show_w > ui_set_canvas) {
                ui_set_canvas = ui_show_w;
            }
            obj_bg.css("width", ui_set_canvas + "px");
            if (b_set_canvas) {
                adapt_canvas_size("width", Math.round(ui_set_canvas / ui_grid));
            }
        }
        if (ui_oh < ui_h) {
            var ui_box_h = $("#mod_box_next").height();
            var ui_show_h = ui_canvasbg_size_h * ui_grid;
            var ui_update_show = ui_h + 100 * ui_grid;

            // 不得设置小于画布当前显示的值
            if (ui_show_h > ui_update_show) {
                ui_update_show = ui_show_h;
            }
            ui_set_canvas = ui_update_show / ui_box_h * 100;
            obj_bg.css("height", ui_set_canvas + "%");
            if (b_set_canvas) {
                adapt_canvas_size("height", Math.round(ui_update_show / ui_grid));
            }
        }
    }
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    设置画布大小
* 参数:
*    @param { Promise<Number> } ui_w 格子数
*    @param { Promise<Number> } ui_h 格子数
* 备注：
*   可同时设置宽高或分别设置（不设置项传入false）
*   设置画布大小时：
*       1.若小于整体模块占位边界大小，将设置为与模块占位边界大小相等值
*       2.若小于视窗大小，将设置为视窗大小+20格长度值
* 返回：
*    @return { Promise<Object> }
*     null 参数错误
*     {W:str_w, H:str_h}
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.10.30
*      内容 : 所有代码
************************************************************************************************/
function mc_set_canvasbg_size(ui_w, ui_h) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_w) && "[object Number]" !== Object.prototype.toString.call(ui_h)) {
        return null;
    }

    // 简易模式 && 标尺
    var b_is_easy_mode_and_has_ruler = obj_item_checkbox_easy_mode.get_dom_val() && has_ruler_and_method("update_coordinate_grid");
    var ui_set_w = ui_w;
    var ui_set_h = ui_h;
    var obj_bg = document.getElementById("mc_box_canvasbg");
    var arr_boundary = get_module_boundary();
    // 边界
    var ui_max_x = arr_boundary[2];
    var ui_max_y = arr_boundary[3];

    // 缩放倍数
    var ui_multiple = ui_mod_box_scale / 100;
    var obj_box = document.getElementById("mod_box_next");
    // 最大格子宽度 当前格子大小
    var ui_grid_w = Number(obj_box.getAttribute("grid_w"));
    // 边界格子数
    var ui_size_w = ui_max_x / ui_grid_w;
    var ui_size_h = ui_max_y / ui_grid_w;
    // 效验后格子数
    var ui_compute_w = 0;
    var ui_compute_h = 0;
    // 是否更新画布显示大小
    var b_update_edit_w = false;
    var b_update_edit_h = false;
    var b_update_width = false;
    var b_update_height = false;
    var ui_width = null;
    var ui_heigt = null;
    var obj_first_size = get_fisrt_mod_size(obj_bg.parentElement);

    ui_size_w = get_boundary_grid_num(ui_size_w, obj_first_size.W);
    ui_size_h = get_boundary_grid_num(ui_size_h, obj_first_size.H);


    // 不小于当前模块位置----
    if (ui_w) {
        b_update_width = true;
        if (ui_w < ui_size_w) {
            ui_compute_w = Math.round(ui_size_w);
            b_update_edit_w = true;
        } else {
            ui_compute_w = ui_w;
        }
    }

    if (ui_h) {
        b_update_height = true;
        if (ui_h < ui_size_h) {
            ui_compute_h = Math.round(ui_size_h);
            b_update_edit_h = true;
        } else {
            ui_compute_h = ui_h;
        }
    }

    // 不小于视窗----
    if (b_update_width) {
        var ui_window_w = obj_box.offsetWidth / ui_multiple / ui_grid_w;

        if (!b_is_easy_mode_and_has_ruler) {
            if (ui_compute_w < ui_window_w) {
                ui_compute_w = Math.round(ui_window_w) + 20;
                b_update_edit_w = true;
            }
        }

        // 记录画布显示大小
        ui_canvasbg_size_w = ui_set_w;

        if (b_update_edit_w) {
            if ("[object Function]" === Object.prototype.toString.call(adapt_canvas_size)) {
                adapt_canvas_size("width", ui_compute_w);
            }
        }

        if (b_is_easy_mode_and_has_ruler) {
            var ui_grid_w_num = (ui_compute_w / obj_first_size.W);

            ui_width = ui_easy_mode_size * ui_grid_w * ui_grid_w_num + "px";
        } else {
            ui_width = ui_compute_w * ui_grid_w + "px";
        }

        obj_bg.style.width = ui_width;
    }

    if (b_update_height) {
        var ui_box_h = obj_box.offsetHeight;
        var ui_window_h = ui_box_h / ui_multiple / ui_grid_w;

        if (!b_is_easy_mode_and_has_ruler) {
            if (ui_compute_h < ui_window_h) {
                ui_compute_h = Math.round(ui_window_h) + 20;
                b_update_edit_h = true;
            }
        }

        ui_canvasbg_size_h = ui_set_h;

        if (b_update_edit_h) {
            if ("[object Function]" === Object.prototype.toString.call(adapt_canvas_size)) {
                adapt_canvas_size("height", ui_compute_h);
            }
        }

        if (b_is_easy_mode_and_has_ruler) {
            var ui_grid_h_num = (ui_compute_h / obj_first_size.H);

            ui_heigt = ui_easy_mode_size * ui_grid_w * ui_grid_h_num / ui_box_h * 100 + "%";
        } else {
            ui_heigt = ui_compute_h * ui_grid_w / ui_box_h * 100 + "%";
        }

        obj_bg.style.height = ui_heigt;
    }

    return {
        W: ui_width,
        H: ui_heigt
    };
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    设置当前画布显示大小
* 参数:
*    @param { Promise<String> } str_type 修改类型
*    @param { Promise<Number> } ui_size 对应大小
* 返回：
*    @return { Promise<Boolean> }
*     false 参数错误
*     true 设置成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.11.16
*      内容 : 所有代码
************************************************************************************************/
function mc_canvasbg_show_size(str_type, ui_size) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_size) || isNaN(ui_size)) {
        return false;
    }
    if ("width" === str_type) {
        ui_canvasbg_size_w = ui_size;
    }
    if ("height" === str_type) {
        ui_canvasbg_size_h = ui_size;
    }
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    获取模块所占位置边界
* 参数:
*    @param { Promise<Boolean> } b_get_size true 获取整体模块位置信息 可为空
*    @param { Promise<Boolean> } b_no_select true 获取未选中模块位置边界 可为空
* 返回：
*    @return { Promise<Array> }
*     [ui_min_x,ui_min_y,ui_max_x,ui_max_y] 边界数组
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.11.12
*      内容 : 所有代码
************************************************************************************************/
function get_module_boundary(b_get_size, b_no_select) {
    var module_list = document.getElementsByClassName("mc_mod");
    var ui_min_x = Math.pow(2, 32);
    var ui_min_y = Math.pow(2, 32);
    var ui_max_x = 0;
    var ui_max_y = 0;

    if (0 === module_list.length) {
        return [0, 0, ui_max_x, ui_max_y];
    }
    for (var idx_module = 0; idx_module < module_list.length; idx_module++) {
        var obj_module = module_list[idx_module];

        if (b_no_select && -1 !== obj_module.className.indexOf("selected")) {
            continue;
        }
        var arr_boundary = mc_tool_compose_boundary(obj_module,ui_min_x,ui_min_y,ui_max_x,ui_max_y);

        ui_min_x = arr_boundary[0];
        ui_min_y = arr_boundary[1];
        ui_max_x = arr_boundary[2];
        ui_max_y = arr_boundary[3];
    }
    if (b_get_size) {
        return [ui_min_x, ui_min_y, ui_max_x - ui_min_x, ui_max_y - ui_min_y];
    }
    return [ui_min_x, ui_min_y, ui_max_x, ui_max_y];
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    比较模块范围工具函数
* 参数:
*    @param { Promise<Object> } obj_module js
*    @param { Promise<Number> } ui_min_x
*    @param { Promise<Number> } ui_min_y
*    @param { Promise<Number> } ui_max_x
*    @param { Promise<Number> } ui_max_y
* 返回：
*    @return { Promise<Array> }
*     [ui_min_x,ui_min_y,ui_max_x,ui_max_y] 边界数组
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2021.7.14
*      内容 : 所有代码
************************************************************************************************/
function mc_tool_compose_boundary(obj_module,ui_min_x,ui_min_y,ui_max_x,ui_max_y) {
    var arr_pot = mc_get_optsize_msg(obj_module, false, true);
    var arr_size = mc_get_optsize_msg(obj_module, true);
    // 偏移减去外接据项偏差
    var u_min_x = arr_pot[0];
    var u_min_y = arr_pot[1];
    var u_max_x = u_min_x + arr_size[0];
    var u_max_y = u_min_y + arr_size[1];

    if (ui_min_x > u_min_x) {
        ui_min_x = u_min_x;
    }
    if (ui_min_y > u_min_y) {
        ui_min_y = u_min_y;
    }
    if (ui_max_x < u_max_x) {
        ui_max_x = u_max_x;
    }
    if (ui_max_y < u_max_y) {
        ui_max_y = u_max_y;
    }
    return [ui_min_x,ui_min_y,ui_max_x,ui_max_y];
}

// 窗口改变更新背景高度 及视窗显示中心坐标
var mc_resizetimer = null;

$(window).resize(function () {
    if (mc_resizetimer) {
        clearTimeout(mc_resizetimer);
    }
    mc_resizetimer = setTimeout(function () {
        if ("function" === typeof update_canvas_h) {
            update_canvas_h(false, ui_canvasbg_size_h);
        }
        ui_box_center_x = $(".mc_mod_box").width() / 2;
        ui_box_center_y = $(".mc_mod_box").height() / 2;
    }, 100);
});

/****************************箱体缩放功能函数*****************************************************/
// 获取模块中心位置延时器 短时间内不重复获取
var mc_scale_scroll_timerout = null;

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    缩小箱体盒子
 * 参数:
 *    @param { Promise<Object> } event 鼠标事件对象
 *    @param { Promise<Number> } ui_mutilation 步进倍数 可为空
 * 返回：
 *    @return { Promise<Boolean> }
 *    true 设置成功
 *    false
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.28
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_mod_sizedown(event,ui_mutilation) {
    var o_parent = document.getElementById("mod_box_next");
    var ui_min_scale = Number(o_parent.getAttribute("min_scale"));

    // 缩放倍数加减时使用整数 设置需/100
    if (ui_mod_box_scale > ui_min_scale) {
        var ui_scale_step = ui_box_scale_step;

        if ("[object Number]" === Object.prototype.toString.call(ui_mutilation)) {
            if (ui_mod_box_scale - ui_scale_step * ui_mutilation > ui_min_scale) {
                ui_scale_step *= ui_mutilation;
            } else {
                ui_scale_step = ui_mod_box_scale - ui_min_scale;
            }
        }
        ui_mod_box_scale -= ui_scale_step;
        // 设置盒子、显示信息缩放/刷新按钮显示隐藏/操作滚动条
        mc_scale_set(event, -ui_scale_step);
        if ("[object Function]" === Object.prototype.toString.call(mc_set_zoom_slider)) {
            mc_set_zoom_slider(-ui_scale_step);
        }
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    放大箱体盒子
 * 参数:
 *    @param { Promise<Object> } event 鼠标事件对象
 *    @param { Promise<Number> } ui_mutilation 步进倍数 可为空
 * 返回：
 *    @return { Promise<Boolean> }
 *    true 设置成功
 *    false
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.28
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_mod_sizeup(event,ui_mutilation) {
    // 缩放倍数加减时使用整数 设置需/100
    if (100 > ui_mod_box_scale) {
        var ui_scale_step = ui_box_scale_step;

        if ("[object Number]" === Object.prototype.toString.call(ui_mutilation)) {
            if (100 > ui_mod_box_scale + ui_scale_step * ui_mutilation) {
                ui_scale_step *= ui_mutilation;
            } else {
                ui_scale_step = 100 - ui_mod_box_scale;
            }
        }
        ui_mod_box_scale += ui_scale_step;
        mc_scale_set(event, ui_scale_step);
        if ("[object Function]" === Object.prototype.toString.call(mc_set_zoom_slider)) {
            mc_set_zoom_slider(ui_scale_step);
        }
    }
    return true;
}

// function mc_set_double_zoom_scroll(obj_origin) {
//     if (obj_origin) {
//         var ui_scrool_x = obj_origin.x + (-obj_origin.x ) * (ui_mod_box_scale / 100);
//         var ui_scrool_y = obj_origin.y + (-obj_origin.y ) * (ui_mod_box_scale / 100);


//         // alert(ui_scrool_x,ui_scrool_y);
//         var obj_box = document.getElementById("mod_box_next").parentNode;

//         obj_box.scrollLeft = ui_scrool_x / (ui_mod_box_scale / 100);
//         obj_box.scrollTop = ui_scrool_y / (ui_mod_box_scale / 100);
//     }
//     return true;
// }

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    缩放设置盒子、显示信息缩放/刷新按钮显示隐藏
 * 参数:
 *    @param { Promise<Object> } event 鼠标事件对象
 *    @param { Promise<Number> } ui_cur_step 缩放加减步进值
 *    @param { Promise<Number> } ui_update_scale 设置缩放到指定缩放倍数 可为空
 * 返回：
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.10
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_scale_set(event, ui_cur_step, ui_update_scale) {
    var o_parent = document.getElementById("mod_box_next");
    var b_set = false;

    if ("[object Number]" === Object.prototype.toString.call(ui_update_scale)) {
        var ui_min_scale = Number(o_parent.getAttribute("min_scale"));

        b_set = true;
        if (ui_min_scale <= ui_update_scale && 100 >= ui_update_scale) {
            ui_mod_box_scale = ui_update_scale;
        }
    }
    // 设置盒子缩放
    o_parent.style.transform = "scale(" + ui_mod_box_scale / 100 + ")";
    document.getElementById("mc_move_layer").style.transform = "scale(" + ui_mod_box_scale / 100 + ")";
    var b_msg_scale = mc_limit_module_len(1000);

    // 模块信息缩放
    if (b_msg_scale) {
        mc_zoom_msg_line();
        mc_scale_scrool(event, ui_cur_step);
        mc_reset_msg_scale("none");
        // 更新画布大小
        // mc_set_canvasbg_size(ui_canvasbg_size_w, false);
        // mc_set_canvasbg_size(false, ui_canvasbg_size_h);
    } else {
        mc_reset_msg_scale("block");
    }
    if (b_set) {
        if ("[object Function]" === Object.prototype.toString.call(mc_set_zoom_slider)) {
            mc_set_zoom_slider(0,false,b_create_grid ? ui_update_scale.toFixed() : ui_update_scale.toFixed(1));
        }
    }
    mc_zoom_coordinate_grid(ui_mod_box_scale);
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    当前模块数量是否小于设定数量
 * 参数:
 *    @param { Promise<Number> } ui_limit_len 模块数量上限
 * 返回：
 *    @return { Promise<Boolean> }
 *    true 小于/等于设定数量
 *    false 大于
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.10
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_limit_module_len(ui_limit_len) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_limit_len)) {
        return false;
    }
    var ui_len = document.getElementsByClassName("mc_mod").length;

    if (ui_limit_len < ui_len) {
        return false;
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    显示隐藏模块信息刷新按钮
 * 参数:
 *    @param { Promise<String> } str_display "block"/"none"
 * 返回：
 *    @return { Promise<Boolean> }
 *    true 设置成功
 *    false 无此元素
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.10
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_reset_msg_scale(str_display) {
    var obj_reset_btn = document.getElementById("mc_scale_reset_btn");

    if (0 === obj_reset_btn.length) {
        return false;
    }
    obj_reset_btn.style.display = str_display;
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    缩放显示信息
 * 参数:
 *    @param { Promise<Object> } o_e 鼠标事件对象
 * 返回：
 *    @return { Promise<Boolean> }
 *    true 设置成功
 *    false
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.28
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_zoom_msg_line() {
    var ui_box_scale = ui_mod_box_scale / 100;
    var ui_multiple = 1 / (ui_box_scale);
    var str_scale = "transform:scale(" + ui_multiple + ")";
    // 样式表
    var str_remove_name = "mod_msg_scale";
    // 处理小数点
    var new_class_name = str_remove_name + "_" + String(ui_mod_box_scale).replace(/\./g, "X");

    // 缩放信息标识-----------
    mc_update_css_rules("theme_mc_box", "." + new_class_name, str_scale + " !important;", true);
    change_block_bgc($(".mc_mod").children(".mod_msg_box"), new_class_name, str_remove_name);
    change_block_bgc($(".mc_mod").children(".mod_hub_box"), new_class_name, str_remove_name);
    change_block_bgc($(".mc_mod").children(".mc_mod_right_top"), new_class_name, str_remove_name);

    if (!b_create_grid) {
        // 卡下标
        change_block_bgc($(".mc_mod").children(".mc_mod_right_bto"), new_class_name, str_remove_name);
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    添加缩放显示信息css规则
 * 参数:
 *    @param { Promise<Object> } o_e 鼠标事件对象
 * 返回：
 *    @return { Promise<Boolean> }
 *    true 设置成功
 *    false
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.28
 *      内容 : 所有代码
 ************************************************************************************************/
// function mc_zoom_add_css_rules() {
//     var o_parent = document.getElementById("mod_box_next");
//     var ui_min_scale = parseInt(o_parent.getAttribute("min_scale"), 10);
//     var ui_scale = 100;

//     for ( ui_scale; ui_scale > ui_min_scale; ) {
//         var ui_box_scale = ui_scale / 100;
//         var ui_multiple = 1 / (ui_box_scale);
//         var str_scale = "transform:scale(" + ui_multiple + ") translateZ(0)";
//         // 处理小数点
//         var new_class_name = "mod_msg_scale_" + String(ui_scale.toFixed(ui_zoom_digit)).replace(/\./g,"X");

//         mc_add_css_rules("theme_mc_box", "." + new_class_name, str_scale + " !important;");
//         ui_scale -= ui_box_scale_step;
//     }
//     return true;
// }

// 以鼠标为中心控制滚动条 滚轮事件对象 是否正在放大****待修
// function mc_mouse_center_scroll(event,b_up) {
//     var obj_box = document.getElementById("mod_box_next").parentNode;

//     if (!obj_box) {
//         return false;
//     }
//     var eve = event || window.event;
//     var ui_wx = eve.clientX;
//     var ui_wy = eve.clientY;
//     var ui_d_left = obj_box.offsetLeft;
//     var ui_d_top = obj_box.offsetTop;
//     var ui_d_width = obj_box.clientWidth;
//     var ui_d_height = obj_box.clientHeight;

//     if (ui_wx < ui_d_left || ui_wy < ui_d_top || ui_wx > (ui_d_left + ui_d_width) || ui_wy > (ui_d_top + ui_d_height)) {
//         //不在内
//         return false;
//     }
//     // 鼠标在箱体中的位置
//     obj_box = $(obj_box);
//     // var ui_box_scale = ui_mod_box_scale / 100;
//     // 视窗显示中心坐标
//     // var ui_center_x = ui_box_center_x / ui_box_scale;
//     // var ui_center_y = ui_box_center_y / ui_box_scale;
//     var ui_mouse_l = ui_wx - ui_d_left;
//     var ui_mouse_t = ui_wy - ui_d_top;

//     var scroll_t = obj_box.scrollTop();
//     var scroll_l = obj_box.scrollLeft();
//     var ui_grid_w = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));
//     var ui_multiple = Math.floor(3 / ui_grid_w * 100);

//     ui_multiple = 1 / (ui_multiple / 100);

//     // ui_multiple = 1 / (ui_box_scale);
//     // var ui_grid_w = 26;
//     // var ui_grid_w = 26 / (ui_mod_box_scale / 100);


//     // 滚动操作--------------
//     var ui_scroll_x = ui_mouse_l * ui_multiple;
//     var ui_scroll_y = ui_mouse_t * ui_multiple;
//     var ui_pnt_l = 0;
//     var ui_pnt_t = 0;

//     // console.log("鼠标原始位置：",ui_mouse_l,ui_mouse_t,"鼠标位置计算：",ui_scroll_x,ui_scroll_y,"滚动距离：",scroll_l,scroll_t);
//     // ui_pnt_l = (ui_scroll_x - ui_center_x ) * ui_box_scale;
//     // ui_pnt_t = (ui_scroll_y - ui_center_y ) * ui_box_scale;
//     // ui_pnt_l = ui_scroll_x * ui_box_scale;
//     // ui_pnt_t = ui_scroll_y * ui_box_scale;


//     if (b_up) {
//         ui_pnt_l = scroll_l + (ui_scroll_x / ui_grid_w);
//         ui_pnt_t = scroll_t + (ui_scroll_y / ui_grid_w);
//     } else {
//         ui_pnt_l = scroll_l - (ui_scroll_x / ui_grid_w);
//         ui_pnt_t = scroll_t - (ui_scroll_y / ui_grid_w);
//     }
//     obj_box.scrollTop(ui_pnt_t);
//     obj_box.scrollLeft(ui_pnt_l);
//     return true;
// }

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    缩放控制滚动条 以选中模块为中心||无选中以模块为中心 否则不改变
 * 参数:
 *    无
 * 返回：
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.10
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_scale_scrool1() {
    var ui_box_scale = ui_mod_box_scale / 100;
    var obj_scroll_box = $(".mc_mod_box").parent();

    // 滚动操作--------------
    // 视窗显示中心坐标
    var ui_center_x = ui_box_center_x / ui_box_scale;
    var ui_center_y = ui_box_center_y / ui_box_scale;
    var len = document.getElementsByClassName("mc_mod").length;

    if (mc_scale_scroll_timerout) {
        clearTimeout(mc_scale_scroll_timerout);
    }

    if (0 !== len) {
        var ui_scroll_x = false;
        var ui_scroll_y = false;

        if (!obj_module_center_xy) {
            var obj_zoom_datum = mc_mouse_pointer_pnt();

            obj_module_center_xy = obj_zoom_datum.ary_datum;
        }

        // 模块中心坐标
        ui_scroll_x = obj_module_center_xy[0];
        ui_scroll_y = obj_module_center_xy[1];

        // console.log("模块在视窗中心：",ui_scroll_x,ui_scroll_y,"鼠标位置：",window.event.clientX - offset_box.left,window.event.clientY - offset_box.top);
        // console.log("缩放倍数：",ui_mod_box_scale,"滚动距离：",obj_scroll_box.scrollLeft(),obj_scroll_box.scrollTop(),window.event);
        // 保持模块在视窗中心
        ui_scroll_x = (ui_scroll_x - ui_center_x) * ui_box_scale;
        ui_scroll_y = (ui_scroll_y - ui_center_y) * ui_box_scale;

        obj_scroll_box.scrollTop(ui_scroll_y);
        obj_scroll_box.scrollLeft(ui_scroll_x);
    }

    mc_scale_scroll_timerout = setTimeout(function () {
        obj_module_center_xy = null;
        clearTimeout(mc_scale_scroll_timerout);
    }, 1000);
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    滚轮进行缩放时 以鼠标中心为基准进行缩放
 * 参数:
 *    @param { Promise<Object> } event 鼠标事件对象
 *    @param { Promise<Number> } ui_cur_step 缩放加减步进值
 * 返回：
 *    @return { Promise<Boolean> }
 *      true 设置成功
 *      false 当前不是滚轮缩放
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.23
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_scale_scrool(event, ui_cur_step) {
    if (("[object WheelEvent]" !== Object.prototype.toString.call(event) && "[object TouchEvent]" !== Object.prototype.toString.call(event))) {
        return false;
    }
    if ("[object Number]" !== Object.prototype.toString.call(ui_cur_step)) {
        return false;
    }
    var obj_box = document.getElementById("mod_box_next").parentNode;
    // var len = document.getElementsByClassName("mc_mod").length;

    if (obj_box) {
        if (obj_mouse_pot.b_keyup) {
            obj_mouse_pot.b_keyup = false;
            obj_mouse_pot.ui_clientx = event.clientX;
            obj_mouse_pot.ui_clienty = event.clientY;
        }
        var ui_scroll_l = obj_box.scrollLeft;
        var ui_scroll_t = obj_box.scrollTop;
        var ui_mouse_l = obj_mouse_pot.ui_clientx - obj_box.offsetLeft + ui_scroll_l;
        var ui_mouse_t = obj_mouse_pot.ui_clienty - obj_box.offsetTop + ui_scroll_t;
        var ui_box_scale = ui_mod_box_scale / 100;
        var ui_box_prev_scale = (ui_mod_box_scale - ui_cur_step) / 100;
        // 计算偏差
        var ui_scroll_x = (ui_mouse_l / ui_box_prev_scale - ui_mouse_l / ui_box_scale) * ui_box_scale;
        var ui_scroll_y = (ui_mouse_t / ui_box_prev_scale - ui_mouse_t / ui_box_scale) * ui_box_scale;

        obj_box.scrollLeft = ui_scroll_l + ui_scroll_x;
        obj_box.scrollTop = ui_scroll_t + ui_scroll_y;
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取当前背景缩放倍数 真实倍数需/100
 * 参数:
 *    无
 * 返回：
 *    @return { Promise<Number> }
 *    缩放倍数
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.28
 *      内容 : 所有代码
 ************************************************************************************************/
function get_box_scale_multiple() {
    if (!ui_mod_box_scale || isNaN(ui_mod_box_scale)) {
        return 100;
    }
    return ui_mod_box_scale;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    获取元素transform属性值 可获取旋转角度与缩放数值
* 参数:
*    @param { Promise<Object> } obj_target js
*    @param { Promise<String> } str_type 获取数值类型 "scale"-缩放倍数 "rotate"-旋转角度
* 返回：
*    @return { Promise<Number> }
*     false 参数有误
*     Number 对应属性数值
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.11.26
*      内容 : 所有代码
************************************************************************************************/
function mc_get_transform_val(obj_target, str_type) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target)) {
        return false;
    }

    var obj_style = window.getComputedStyle(obj_target, null);
    // transform 矩阵 如(0.866025, 0.5, -0.5, 0.866025, 0px, 0px)
    var trix = obj_style.getPropertyValue("-webkit-transform") ||
        obj_style.getPropertyValue("-moz-transform") ||
        obj_style.getPropertyValue("-ms-transform") ||
        obj_style.getPropertyValue("-o-transform") ||
        obj_style.getPropertyValue("transform") ||
        "FAIL";

    var values = trix.split("(")[1].split(")")[0].split(",");
    var a = values[0];
    var b = values[1];
    // var c = values[2];
    // var d = values[3];

    if ("scale" === str_type) {
        return Math.sqrt(a * a + b * b);
    }
    if ("rotate" === str_type) {
        //  var sin = b / scale;
        return Math.round(Math.atan2(b, a) * (180 / Math.PI));
    }
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    获取元素transform 设置对应缩放后矩阵
* 参数:
*    @param { Promise<Object> } obj_target js
*    @param { Promise<Number> } ui_scale 缩放倍数
* 返回：
*    @return { Promise<String> }
*     false 参数有误
*     string 对应属性数值
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.11.26
*      内容 : 所有代码
************************************************************************************************/
// function mc_get_transform_matrix(obj_target, ui_scale) {
//     if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target) || "[object Number]" !== Object.prototype.toString.call(ui_scale)) {
//         return false;
//     }

//     var obj_style = window.getComputedStyle(obj_target, null);
//     // transform 矩阵 如(0.866025, 0.5, -0.5, 0.866025, 0px, 0px)
//     var trix = obj_style.getPropertyValue("-webkit-transform") ||
//         obj_style.getPropertyValue("-moz-transform") ||
//         obj_style.getPropertyValue("-ms-transform") ||
//         obj_style.getPropertyValue("-o-transform") ||
//         obj_style.getPropertyValue("transform") ||
//         "FAIL";

//     // console.log("matrix",trix);
//     if ("none" === trix) {
//         obj_target.style.transform = "scale(" + ui_scale + ")";
//         return true;
//     }
//     var values = trix.split("(")[1].split(")")[0].split(",");

//     if (6 < values.length) {
//         // 3D
//         values[5] = ui_scale;
//         values[15] = ui_scale;
//     } else {
//         values[0] = ui_scale;
//         values[3] = ui_scale;
//     }

//     obj_target.style.transform = "matrix(" + values.join(",") + ")";
//     return true;
// }

// // 显示信息缩放
// function mc_set_msg_scale(arr_module_list) {
//     if ("[object HTMLCollection]" !== Object.prototype.toString.call(arr_module_list) && "[object Array]" !== Object.prototype.toString.call(arr_module_list)) {
//         return false;
//     }

//     for (var j = 0; j < arr_module_list.length; j++) {
//         var child_list = arr_module_list[j].childNodes;

//         for (var i = 0; i < child_list.length; i++) {
//             mc_get_transform_matrix(child_list[i], 1 / (ui_mod_box_scale / 100));
//         }
//     }
//     return true;
// }

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    放大缩小 创建模组时 获取canvas url背景字串
 * 参数:
 *    @param { Promise<Number> } ui_div_width 模组宽
 *    @param { Promise<Number> } ui_div_height 模组高
 *    @param { Promise<Array> } ary_pix 模组高亮点坐标数组
 * 返回：
 *    @return { Promise<String> }
 *     url背景字串
 * 备注：
 *    如果性能过低可考虑优化画法 只画虚点/实点，填充背景直接画网格线
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.03.26
 *      内容 : 所有代码
 ************************************************************************************************/
function set_mod_bgimg(ui_div_width, ui_div_height, ary_pix) {
    var ui_current_size = document.getElementById("mod_box_next").getAttribute("grid_w");
    // create background image
    var canvas = document.createElement("canvas");
    var ctx = canvas.getContext("2d");
    var canvas_select = document.createElement("canvas");
    var ctx_select = canvas_select.getContext("2d");

    ui_current_size = parseInt(ui_current_size, 10);
    // set size
    canvas.width = ui_div_width;
    canvas.height = ui_div_height;
    canvas_select.width = ui_div_width;
    canvas_select.height = ui_div_height;

    // draw background
    ctx.fillStyle = "rgb(140, 155, 240)";
    ctx_select.fillStyle = "rgba(245,241,35,1)";
    ctx.lineWidth = 1;
    ctx_select.lineWidth = 1;
    for (var idx = 0; idx < ary_pix.length; idx++) {
        var ui_offset_x = ary_pix[idx][0] * ui_current_size;
        var ui_offset_y = ary_pix[idx][1] * ui_current_size;
        var ui_start_dot_x = ui_offset_x + ui_current_size - 1;
        var ui_start_dot_y = ui_offset_y + ui_current_size;

        ctx.fillRect(ui_offset_x, ui_offset_y, ui_current_size, ui_current_size);

        ctx.beginPath();
        ctx.moveTo(ui_start_dot_x, ui_offset_y);
        ctx.lineTo(ui_start_dot_x, ui_start_dot_y);
        ctx.lineTo(ui_offset_x, ui_start_dot_y);
        ctx.stroke();

        ctx_select.fillRect(ui_offset_x, ui_offset_y, ui_current_size, ui_current_size);

        ctx_select.beginPath();
        ctx_select.moveTo(ui_start_dot_x, ui_offset_y);
        ctx_select.lineTo(ui_start_dot_x, ui_start_dot_y);
        ctx_select.lineTo(ui_offset_x, ui_start_dot_y);
        ctx_select.stroke();
    }
    var str_img_url = canvas.toDataURL();
    var str_img_urlselect = canvas_select.toDataURL();

    // return str_img_url;
    return [str_img_url, str_img_urlselect];
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取滚轮缩放基准点 (以选中模块中点为基准点,无选中以模块中心为基点)
 * 参数:
 *    NA
 * 返回：
 *     @return { Promise<Array> }
 *      {[基准点XY]}
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.4
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_mouse_pointer_pnt() {
    // 边界数据
    var obj_boundary = get_boundary_obj(arr_select_mod);
    // var o_box = $(document.getElementById("mod_box_next").parentNode);

    if (!obj_boundary) {
        obj_boundary = get_boundary_obj($(".mc_mod"));
        if (!obj_boundary) {
            return false;
        }
    }

    // 基准点为 选中模块/模块中心
    var ui_boundary_left = obj_boundary.ui_boundary_left;
    var ui_max_top_t = obj_boundary.ui_max_top_t;
    var ui_datum_l = (obj_boundary.ui_boundary_right + obj_boundary.ui_max_right_w - ui_boundary_left) / 2 + ui_boundary_left;
    var ui_datum_t = (obj_boundary.ui_boundary_bot - ui_max_top_t) / 2 + ui_max_top_t;


    // {[基准点XY],[整体模块WH]}
    // return { ary_datum: [ui_datum_l - o_box.scrollLeft(), ui_datum_t - o_box.scrollTop()], ary_max_size: [obj_boundary.ui_boundary_right + obj_boundary.ui_max_right_w, obj_boundary.ui_boundary_bot] };
    return { ary_datum: [ui_datum_l, ui_datum_t] };
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    放大缩小修改模组背景及位置
 * 参数:
 *    @param { Promise<Number> } arr_mod 模���数组
 *    @param { Promise<Number> } ui_current_size 背景格子宽度
 * 返回：
 *    无
 * 备注：
 *    如果性能过低可考虑优化画法 只画虚点/实点，填充背景直接画网格线
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.03.26
 *      内容 : 所有代码
 ************************************************************************************************/
function create_fill_img(arr_mod, ui_current_size) {
    var ary_get_img_url = {};

    if ("string" === typeof ui_current_size) {
        ui_current_size = parseInt(ui_current_size, 10);
    }

    for (var idx_mod = 0; idx_mod < arr_mod.length; idx_mod++) {
        var o_mod = arr_mod[idx_mod];
        var str_mod_id = o_mod.getAttribute("mod_id");
        var mod_left = 0;
        var mod_top = 0;
        var mod_pot = "";
        var str_transform = o_mod.getAttribute("transform_msg");
        var ui_lc = 0;
        var ui_tc = 0;

        // 修改位置卡格
        if (str_transform) {
            var arr_size = mc_analysis_transform_msg(o_mod);

            // 变换元素扣除偏差
            ui_lc = Number(arr_size[2]);
            ui_tc = Number(arr_size[3]);
        }

        o_mod.setAttribute(str_mod_attr_easy_mode, false);


        if (obj_item_checkbox_easy_mode.get_dom_val()) {
            return;
        }

        if (0 < idx_mod && ary_get_img_url[str_mod_id]) {
            var arr_val = ary_get_img_url[str_mod_id];

            // 存在 无需创建
            o_mod.style.width = arr_val[0] + "px";
            o_mod.style.height = arr_val[1] + "px";

            if (-1 !== o_mod.className.indexOf("selected")) {
                o_mod.style.backgroundImage = "url(" + arr_val[3] + ")";
            } else {
                o_mod.style.backgroundImage = "url(" + arr_val[2] + ")";
            }

            mod_pot = mc_get_appoint_obj($(o_mod), "mod_pot").innerText;

            if (mod_pot) {
                // 格子数
                mod_left = Number(mod_pot.split(",")[0].trim());
                mod_top = Number(mod_pot.split(",")[1].trim());

                // 修改位置卡格
                o_mod.style.left = mod_left * ui_current_size + ui_lc + "px";
                o_mod.style.top = mod_top * ui_current_size + ui_tc + "px";

                // o_mod.setAttribute("select_tip",arr_val[3]);
                // o_mod.setAttribute("no_select",arr_val[2]);

                // update module msg
                mc_update_module_msg(o_mod.id, mod_left + "," + mod_top, arr_val[0] / ui_current_size + "X" + arr_val[1] / ui_current_size);
            }
        } else {
            var ui_div_width = 0;
            var ui_div_height = 0;
            var arr_item = [];
            var ui_width = o_mod.getAttribute("mod_wg");
            var ui_height = o_mod.getAttribute("mod_hg");
            // 获取对应亮点数组
            // eslint-disable-next-line no-undef
            var ary_pix = mc_layout_get_mod_dot_location(str_mod_id, ARY_MOD_DATA);

            ui_div_width = ui_width * ui_current_size;
            ui_div_height = ui_height * ui_current_size;

            var str_img_url = set_mod_bgimg(ui_div_width, ui_div_height, ary_pix);

            var str_no_select_url = str_img_url[0];
            var str_select_url = str_img_url[1];

            // 保存本次
            arr_item.push(ui_div_width, ui_div_height, str_no_select_url, str_select_url);
            ary_get_img_url[str_mod_id] = arr_item;

            // edit style
            o_mod.style.width = ui_div_width + "px";
            o_mod.style.height = ui_div_height + "px";
            if (-1 !== o_mod.className.indexOf("selected")) {
                o_mod.style.backgroundImage = "url(" + str_select_url + ")";
            } else {
                o_mod.style.backgroundImage = "url(" + str_no_select_url + ")";
            }

            mod_pot = mc_get_appoint_obj($(o_mod), "mod_pot").innerText;

            // 格子数
            mod_left = Number(mod_pot.split(",")[0].trim());
            mod_top = Number(mod_pot.split(",")[1].trim());
            o_mod.style.left = mod_left * ui_current_size + ui_lc + "px";
            o_mod.style.top = mod_top * ui_current_size + ui_tc + "px";
            o_mod.setAttribute("select_tip", str_select_url);
            o_mod.setAttribute("no_select", str_no_select_url);

            // update module msg
            mc_update_module_msg(o_mod.id, mod_left + "," + mod_top, ui_width + "X" + ui_height);
        }
    }
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    放大缩小箱体响应大小及位置
 * 参数:
 *    @param { Promise<Number> } arr_box 箱体数组
 *    @param { Promise<Number> } ui_size 背景格子宽度
 * 返回：
 *    无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.8.17
 *      内容 : 所有代码
 ************************************************************************************************/
function update_box_img(arr_box, ui_size) {
    if ("string" === typeof ui_size) {
        ui_size = Number(ui_size);
    }
    var str_pot = "";
    var mod_left = 0;
    var mod_top = 0;

    for (var idx_box = 0; idx_box < arr_box.length; idx_box++) {
        var obj_box = arr_box[idx_box];
        var str_transform = obj_box.getAttribute("transform_msg");
        var ui_width = Number(obj_box.getAttribute("mod_wg"));
        var ui_height = Number(obj_box.getAttribute("mod_hg"));
        var ui_lc = 0;
        var ui_tc = 0;

        obj_box.setAttribute(str_mod_attr_easy_mode, false);
        obj_box.style.width = ui_width * ui_size + "px";
        obj_box.style.height = ui_height * ui_size + "px";
        str_pot = mc_get_appoint_obj($(obj_box), "mod_pot").innerText;
        mod_left = Number(str_pot.split(",")[0].trim());
        mod_top = Number(str_pot.split(",")[1].trim());
        if (str_transform) {
            var arr_size = mc_analysis_transform_msg(obj_box);

            // 变换元素扣除偏差
            ui_lc = Number(arr_size[2]);
            ui_tc = Number(arr_size[3]);
        }
        obj_box.style.left = mod_left * ui_size + ui_lc + "px";
        obj_box.style.top = mod_top * ui_size + ui_tc + "px";
    }
}

/*******************************模块鼠标事件-框选**************************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    箱体绑定鼠标事件-框选操作
 * 参数:
 *     @param { Promise<String> } mod_box 箱体类名 jq方式传入 此处为".mc_mod_box"
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.06
 *      内容 : 所有代码
 ************************************************************************************************/
// 当前鼠标按住的元素
var obj_down_mod = null;
var boundary_timer_scroll = null;

function mod_select(mod_box) {
    var $mod_box = $(mod_box);

    //  框选事件
    $mod_box[0].removeEventListener(obj_event_type.triggerEvenDown,mc_select_mousedown);
    $mod_box[0].addEventListener(obj_event_type.triggerEvenDown,mc_select_mousedown,{passive: false});
}

function mc_select_mousedown(eventDown) {
    var $this = $(this);
    var b_select = false;

    if (b_istouch) {
        b_select = true;
    } else {
        if (b_box_select) {
            b_select = true;
        }
    }

    var u_mod_box_scale = ui_mod_box_scale / 100;
    var scroll_l = $this.parent().scrollLeft() / u_mod_box_scale;
    var scroll_t = $this.parent().scrollTop() / u_mod_box_scale;
    var box_offset = $this.offset();
    // 相对于外部偏移
    var ui_box_offsetl = box_offset.left;
    var ui_box_offsett = box_offset.top;
    var ui_box_w = $this.width();
    var ui_box_h = $this.height();
    var ui_canvas_l = document.getElementById("mc_hlever_layout_canvas").offsetLeft;
    var ui_canvas_t = document.getElementById("mc_hlever_layout_canvas").offsetTop;
    var str_downtarget_id = eventDown.target.id;

    if (eventDown.ctrlKey) {
        return;
    }
    // 空白位置/锁定元素触发
    var arr_trigger = mc_select_boundary_judge(str_downtarget_id,eventDown);
    var b_lock_trigger = arr_trigger[1];

    if (b_lock_trigger || arr_trigger[0]) {
        var arr_cancel_select = arr_select_mod;
        var arr_lock_select = [];

        if (0 !== $(".mo_select_box").length) {
            $(".mo_select_box").remove();
        }
        if (b_lock_trigger) {
            arr_cancel_select = mc_filter_tool(function (item) {
                return !item.hasClass("mc_lock");
            },arr_select_mod);
            arr_lock_select = mc_filter_tool(function (item) {
                return item.hasClass("mc_lock");
            },arr_select_mod);
        }

        // 若有选中项且为非锁定元素 取消选中
        if (0 !== arr_cancel_select.length) {
            if ("mc_box_canvasbg" === str_downtarget_id || ( b_progress_edit && "mc_edit_border" === str_downtarget_id)) {
                obj_down_mod = null;
            } else if (!obj_down_mod) {
                obj_down_mod = arr_cancel_select[0];
            }
            for (var idx = 0; idx < arr_cancel_select.length; idx++) {
                var o_set_bg = arr_select_mod[idx];

                o_set_bg.removeClass("selected");
                if (b_create_grid) {
                    mc_switch_mod_bg(o_set_bg[0], false);
                }
            }
            // 清空选中模组数组
            arr_select_mod = arr_lock_select;
            mc_clear_zindex();
            // 返回空数组
            box_return_new_value($this, arr_select_mod);
            b_select = false;
        }
        //  创建选框节点
        var $mo_select_box = $('<div class="mo_select_box"></div>');
        //  设置选框的初始位置
        var obj_pot = mc_get_top_fun("mc_get_pnt",eventDown,false,false,true);
        var startX = eventDown.x - ui_box_offsetl || obj_pot.X - ui_box_offsetl;
        var startY = eventDown.y - ui_box_offsett || obj_pot.Y - ui_box_offsett;

        startX /= u_mod_box_scale;
        startY /= u_mod_box_scale;
        $("#mc_box_canvasbg").append($mo_select_box);
        $mo_select_box.css({
            left: startX + scroll_l,
            top: startY + scroll_t
        });
        //  根据鼠标移动，设置选框宽高
        var mose_x = null;
        var mose_y = null;

        //  清除事件冒泡、捕获
        // clearBubble(eventDown);
        var arr_mod = $this.children();

        //  监听鼠标移动事件
        window.addEventListener(obj_event_type.triggerEvenMove,function (eventMove) {
            if (!b_select) {
                return;
            }
            // mobile_timeOutEvent = null;
            if (eventMove.cancelable) {
                eventMove.preventDefault();
            }
            var obj_move_pot = mc_get_top_fun("mc_get_pnt",eventMove,false,false,true);
            var ui_eventMoveX = obj_move_pot.X;
            var ui_eventMoveY = obj_move_pot.Y;
            var ui_move_scroll_l = $this.parent().scrollLeft() / u_mod_box_scale;
            var ui_move_scroll_t = $this.parent().scrollTop() / u_mod_box_scale;

            //  设置选框可见
            $mo_select_box.css("display", "block");
            //  根据鼠标移动，设置选框的位置、宽高
            mose_x = eventMove.x - ui_box_offsetl || ui_eventMoveX - ui_box_offsetl;
            mose_y = eventMove.y - ui_box_offsett || ui_eventMoveY - ui_box_offsett;

            mose_x /= u_mod_box_scale;
            mose_y /= u_mod_box_scale;
            // 滚动条偏移计算
            var ui_scroll_l = ui_move_scroll_l - scroll_l;
            var ui_scroll_t = ui_move_scroll_t - scroll_t;
            var u_dval_l = 0 > ui_scroll_l ? ui_scroll_l : 0;
            var u_dval_t = 0 > ui_scroll_t ? ui_scroll_t : 0;

            //  暂存选框的位置及宽高，用于将 mod 选中
            var select_left = (Math.min(mose_x, startX) + u_dval_l);
            var select_top = (Math.min(mose_y, startY) + u_dval_t);
            var select_width = (Math.abs(mose_x - startX) + Math.abs(ui_scroll_l));
            var select_height = (Math.abs(mose_y - startY) + Math.abs(ui_scroll_t));

            $mo_select_box.css({
                left: select_left,
                top: select_top,
                width: select_width,
                height: select_height
            });

            for (var idx_mod = 0; idx_mod < arr_mod.length - 1; idx_mod++) {
                var obj_item = arr_mod.eq(idx_mod);

                if (obj_item.hasClass("mod_hub_Line") ) {
                    break;
                }
                if ("mc_edit_border" === obj_item.attr("id") || obj_item.is(":hidden")) {
                    continue;
                }
                var ary_size = mc_get_optsize_msg(obj_item[0], true);
                var ary_pot = mc_get_optsize_msg(obj_item[0]);
                var itemX_pos = ary_size[0] + ary_pot[0];
                var itemY_pos = ary_size[1] + ary_pot[1];
                //  判断 mod 是否与选框有交集，添加选中的效果
                var condition1 = itemX_pos > select_left;
                var condition2 = itemY_pos > select_top;
                var condition3 = ary_pot[0] < (select_left + select_width);
                var condition4 = ary_pot[1] < (select_top + select_height);

                mc_select_classtip(condition1,condition2,condition3,condition4,obj_item);
            }

            var js_parent = $this.parent()[0];

            // 非应用程序下 鼠标移出边界控制滚动条移动
            if (!mc_nwjs_check_support()) {
                if ($(eventMove.target).parent() === $(".mc_mod") || $("#mc_box_canvasbg").is(eventMove.target) || $(".mc_mod").is(eventMove.target)) {
                    // 在范围中去除滚动定时
                    clearInterval(boundary_timer_scroll);
                } else {
                    if (ui_canvas_t > ui_eventMoveY) {
                        mc_select_boundary_scrool(js_parent, $mo_select_box[0], 0);
                    }
                    if (ui_box_h < ui_eventMoveY) {
                        mc_select_boundary_scrool(js_parent, $mo_select_box[0], 1);
                    }
                    if (ui_canvas_l > ui_eventMoveX) {
                        mc_select_boundary_scrool(js_parent, $mo_select_box[0], 2);
                    }
                    if (ui_box_w < ui_eventMoveX) {
                        mc_select_boundary_scrool(js_parent, $mo_select_box[0], 3);
                    }
                }
            }
        },{passive: false});

        window.addEventListener(obj_event_type.triggerEvenUp,function (eventUp) {
            if (!b_select) {
                return;
            }
            if (boundary_timer_scroll) {
                clearInterval(boundary_timer_scroll);
            }

            var e = eventUp || window.event;
            var obj = e.target;


            if (obj) {
                mc_box_mouseevent_bubble(e);
                if (obj_mousedown) {
                    // 点击标尺
                    if (has_ruler_and_method("on_mouse_up")) {
                        obj_box_coordinate_ruler.on_mouse_up(e);
                    }
                    return;
                }
                if (b_select) {
                    if (e.cancelable) {
                        e.preventDefault();
                    }
                    mod_select_end($this, $mo_select_box, obj_down_mod, b_ctrl_select);
                }
            }
            b_select = false;
        },{passive: false});
    }
}

function mc_select_classtip(condition1,condition2,condition3,condition4,obj_item) {
    if (condition1 && condition2 && condition3 && condition4) {
        if (!obj_item.hasClass("selected")) {
            obj_item.addClass("temp_selected");
        }
    } else {
        obj_item.removeClass("temp_selected");
    }
    return true;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    框选时 鼠标移出边界控制滚动条移动
 * 参数:
 *     @param { Promise<Object> } parent 滚动条所在js元素
 *     @param { Promise<Object> } mo_select_box 选框js元素
 *     @param { Promise<Number> } ui_index 滚动方向及类型
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.16
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_select_boundary_scrool(parent, mo_select_box, ui_index) {
    if (boundary_timer_scroll) {
        clearInterval(boundary_timer_scroll);
    }
    var u_parent_h = document.getElementById("mc_box_canvasbg").offsetHeight;
    var u_parent_w = document.getElementById("mc_box_canvasbg").offsetWidth;

    boundary_timer_scroll = setInterval(function () {
        if (0 === ui_index && u_parent_h > parent.scrollTop && 0 < parent.scrollTop) {
            parent.scrollTop -= 10;
            mo_select_box.style.top = mo_select_box.offsetTop - 10 + "px";
            mo_select_box.style.height = mo_select_box.offsetHeight + 10 + "px";
        }
        if (1 === ui_index && u_parent_h > parent.scrollTop) {
            parent.scrollTop += 10;
            mo_select_box.style.height = mo_select_box.offsetHeight + 10 + "px";
        }
        if (2 === ui_index && u_parent_w > parent.scrollLeft && 0 < parent.scrollLeft) {
            parent.scrollLeft -= 10;
            mo_select_box.style.left = mo_select_box.offsetLeft - 10 + "px";
            mo_select_box.style.width = mo_select_box.offsetWidth + 10 + "px";
        }
        if (3 === ui_index && u_parent_w > parent.scrollLeft) {
            parent.scrollLeft += 10;
            mo_select_box.style.width = mo_select_box.offsetWidth + 10 + "px";
        }
    }, 10);
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    箱体绑定鼠标事件-框选结束操作
 * 参数:
 *     @param { Promise<Object> } obj_box $(".mc_mod_box") 框选事件绑定元素
 *     @param { Promise<Object> } obj_frame $(".mo_select_box") 款选虚拟框
 *     @param { Promise<Object> } obj_down_target 当前单击选中元素
 *     @param { Promise<Boolean> } b_ctrl_select 是否整理元素顺序 默认整理 可为空
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.9.22
 *      内容 : 所有代码
 ************************************************************************************************/
function mod_select_end(obj_box, obj_frame, obj_down_target) {
    $(window).off(obj_event_type.triggerEvenMove);
    arr_select_mod = [];
    obj_box.find(".mc_mod.temp_selected").removeClass("temp_selected").addClass("selected");
    var ary_select = $(".selected");

    for (var idx = 0; idx < ary_select.length; idx++) {
        var obj_jq = ary_select.eq(idx);

        arr_select_mod.push(obj_jq);
        mc_switch_mod_bg(obj_jq[0], true);
    }
    if (obj_down_target && 0 === arr_select_mod.length) {
        obj_down_target.addClass("selected");
        mc_switch_mod_bg(obj_down_mod[0], true);
        arr_select_mod.push(obj_down_target);
    }
    obj_frame.remove();

    if (0 !== arr_select_mod.length) {
        // 返回框选数组
        if (!b_ctrl_select) {
            arr_select_mod = set_arr_select_mod(true);
        } else {
            b_ctrl_select = false;
        }
        // console.log("框选结束",obj_box,arr_select_mod);
        box_return_new_value(obj_box, arr_select_mod);
        mc_select_item_add_zindex(arr_select_mod);
        if ("[object Function]" === Object.prototype.toString.call(mc_select_end_show_menu)) {
            mc_select_end_show_menu(arr_select_mod[0][0]);
        }
    }
}

/*******************************模组鼠标事件-拖拽**************************************************/
// 黏合延时器 拖拽一段时间后开始黏合
var fn_draw_settimeout = null;
// 是否开启黏合 true开启
var b_open_adhesions = false;
// 黏合延时结束标识 true延时结束 开始黏合
var b_settimeout_adhesions = false;

// optimize draw start ------------------------
// 移动真实模块位置信息，rsfX/Y与外接矩形偏差、
// [{BLK:obj_js,X:offsetleft,Y:offsettop,tsfX:0,tsfY:0}]
var ary_selected_items = [];
// 拖拽起始鼠标位置
var obj_base_pnt = {};
// 移动外接矩形数据{OBJ:obj_js,X:offsetLeft,Y:offsetTop,W:offsetWidth,H:offsetHeight}
var obj_mov = {};
// 右、下移动边界距离 {X:0,Y:0}:(画布大小-移动矩形大小)
var obj_draw_boundary = {};
// 移动操作记录 {operate_param:obj, arr_no_select_msg:arr} arr_no_select_msg未选中模块整体信息
var obj_mov_operate_param = {};
var ui_mov_grid_w = 0;

// 双指缩放
var arr_double_zoom_start_dot = [];
var obj_double_finger_zoom = {};
var ui_before_zoom = -1;
var b_double_zoom = false;

// 清空拖拽参数
function clear_mov_param() {
    ary_selected_items = [];
    obj_base_pnt = {};
    obj_mov = {};
    obj_draw_boundary = {};
    obj_mov_operate_param = {};
    ui_mov_grid_w = 0;
}

// mod draw
function mc_mod_mousedown(eve, dom) {
    if (b_double_zoom) {
        return false;
    }
    // 移动端点击未选中元素 退出（此时应为滑动条操作）
    // 记录当前滚动条位置
    if (!b_istouch && !mc_judge_module_b_select(dom,"selected",2)) {
        obj_base_pnt = mc_get_top_fun("mc_get_pnt",eve,false,false,true);
        return false;
    }
    var str_id = dom.attributes.id.value;

    if (!str_id || 0 === str_id.length) {
        return false;
    }
    var even = eve || window.event;
    // 选择/拖拽复制操作--
    var select_or_copy_return = mc_select_or_copy_judge(dom, even);

    // 正在连线：只进行选择--
    if (b_connection) {
        return false;
    }
    // 操作记录
    var operate_param = null;

    // 操作判断：拖拽复制/选中--
    if ("[object Object]" === Object.prototype.toString.call(select_or_copy_return)) {
        // 进行了拖拽复制
        operate_param = select_or_copy_return;
    } else if (select_or_copy_return) {
        // 进行了选中判断
        operate_param = new mc_layout_operate_format_data();
        operate_param.obj_list = mc_transform_id_data(arr_select_mod);
    }

    if (!operate_param) {
        // param error
        return false;
    }
    // 显示移动块 记录移动前真实块位置
    operate_param.undo = mc_save_data_set_moveblk(even);
    obj_mov_operate_param.operate_param = operate_param;
    obj_mov_operate_param.arr_no_select_msg = mc_get_modulemsg_set_adhesions();
    // mc_menu_exhibit(true);
    eve.preventDefault();
    return false;
}

if (b_istouch) {
    window.onmousemove = function (e) {
        mc_module_draw_move(e);
        return true;
    };

    window.onmouseup = function (e) {
        mc_module_draw_up(e);
    };
} else {
    window.addEventListener("touchstart",mc_double_zoom_touchstart);
    window.addEventListener("touchmove", function (e) {
        mc_module_draw_move(e);
    }, { passive: false });
    window.addEventListener("touchend", function (e) {
        mc_module_draw_up(e);
    }, { passive: false });
}

function mc_module_draw_move(event_move) {
    if (!mc_double_zoom_touchmove(event_move)) {
        return false;
    }
    if (0 === ary_selected_items.length) {
        return false;
    }
    var e_move = event_move || window.event_move;
    var ui_box_sacle = ui_mod_box_scale / 100;
    var obj_new_pnt = mc_get_top_fun("mc_get_pnt",e_move,false,false,true);
    var i_offset_x = (obj_new_pnt.X - obj_base_pnt.X) / ui_box_sacle;
    var i_offset_y = (obj_new_pnt.Y - obj_base_pnt.Y) / ui_box_sacle;
    // 移动距离
    var obj_move_grid = get_move_grid(obj_mov.X + i_offset_x, obj_mov.Y + i_offset_y, true);
    var ui_x = obj_move_grid.ui_x;
    var ui_y = obj_move_grid.ui_y;

    // 边界处理
    ui_x = 0 > ui_x ? 0 : ui_x = (obj_draw_boundary.X < ui_x ? obj_draw_boundary.X : ui_x);
    ui_y = 0 > ui_y ? 0 : ui_y = (obj_draw_boundary.Y < ui_y ? obj_draw_boundary.Y : ui_y);

    obj_mov.OBJ.style.left = ui_x + "px";
    obj_mov.OBJ.style.top = ui_y + "px";

    // 黏合处理
    if (b_settimeout_adhesions) {
        mc_mov_set_adhesions_return_data(ui_x, ui_y);
    }
    mc_edit_boundary_handle(obj_mov.W,obj_mov.H,ui_x,ui_y);
    e_move.preventDefault();
    return false;
}

function mc_module_draw_up(e) {
    var even = e || window.event;

    if (!mc_double_zoom_touchend()) {
        return false;
    }
    // 移动端未选中元素 鼠标抬起则为选中
    if (!b_istouch) {
        var obj_target = mc_judge_module_b_select(e.target,"mc_mod",0);
        var obj_new_pot = mc_get_top_fun("mc_get_pnt",even,false,false,true);

        // 当前点击为module 且module未选中
        if (obj_target && !mc_judge_module_b_select(obj_target,"selected",2) && obj_new_pot.X === obj_base_pnt.X && obj_new_pot.Y === obj_base_pnt.Y) {
            obj_base_pnt = {};
            mc_set_mouse_pot(obj_new_pot);
            arr_select_mod.push($(obj_target));
            obj_target.classList.add("selected");
            mc_switch_mod_bg(obj_target, true);
            box_return_new_value($("#mod_box_next"), arr_select_mod);
            return false;
        }
    }
    if (0 === ary_selected_items.length) {
        return false;
    }

    var i_offset_x = obj_mov.OBJ.offsetLeft - obj_mov.X;
    var i_offset_y = obj_mov.OBJ.offsetTop - obj_mov.Y;
    // 移动格子数
    var u_x = i_offset_x / ui_mov_grid_w;
    var u_y = i_offset_y / ui_mov_grid_w;
    var arr_redo_pot = [];
    // 出界鼠标抬起 拖拽还未结束处理
    var b_out_handle = false;

    // 记录鼠标位置
    mc_set_mouse_pot(mc_get_top_fun("mc_get_pnt",even,false,false,true));
    // 未移动
    if (0 === u_x && 0 === u_y && !obj_item_checkbox_easy_mode.get_dom_val()) {
        if (obj_mov.OBJ ) {
            obj_mov.OBJ.style.display = "none";
        }

        clear_mov_param();
        mc_menu_exhibit();
        return true;
    }

    if (even.ctrlKey) {
        mc_set_mov_copy_blk(i_offset_x, i_offset_y, u_x, u_y);
        mov_end("curd");
        return true;
    }
    if (!arr_select_mod.length ) {
        b_out_handle = true;
    }
    for (var idx = 0; idx < ary_selected_items.length; idx++) {
        var obj_mod = ary_selected_items[idx];

        obj_mod.BLK.style.left = (obj_mod.X + i_offset_x) + "px";
        obj_mod.BLK.style.top = (obj_mod.Y + i_offset_y) + "px";
        // 更新显示及保存数据
        arr_redo_pot.push(update_show_and_data(obj_mod.BLK, u_x, u_y, obj_mod));
        if (b_out_handle) {
            arr_select_mod.push($(obj_mod.BLK));

            $(obj_mod.BLK).addClass("selected");
            mc_switch_mod_bg(obj_mod.BLK, true);
        }
    }
    obj_mov_operate_param.operate_param.redo = arr_redo_pot;

    mov_end("move");
    return true;

    // 移动结束返回
    function mov_end(str_operate_type) {
        if (obj_mov.OBJ) {
            obj_mov.OBJ.style.display = "none";
        }
        var ui_mov_blkl = obj_mov.X + i_offset_x;
        var ui_mov_blkt = obj_mov.Y + i_offset_y;
        var o_move_operate_param = JSON.parse(JSON.stringify(obj_mov_operate_param));

        // operate_param操作记录 移动/拖拽复制 operate_type记录操作类型
        box_return_new_value($("#mod_box_next"),
            {
                arr_select: arr_select_mod,
                operate_param: o_move_operate_param.operate_param,
                operate_type: str_operate_type,
                module_msg: [ui_mov_blkl, ui_mov_blkt, ui_mov_blkl + obj_mov.W, ui_mov_blkt + obj_mov.H],
                noselect_boundary: o_move_operate_param.arr_no_select_msg
            }, true);
        clear_mov_param();
        return true;
    }
}

/*******************************双指缩放相关**************************************************/
// 判断是否双指缩放
function mc_double_zoom_touchstart(eve) {
    if (!b_istouch && 2 <= eve.touches.length) {
        b_double_zoom = true;
        eve.preventDefault();
        arr_double_zoom_start_dot = eve.touches;
        return false;
    }
    return true;
}

function mc_double_zoom_touchmove(eve) {
    if (b_double_zoom && 2 <= eve.touches.length) {
        eve.preventDefault();
        var arr_double_zoom_end_dot = eve.touches;
        // 缩放比例
        var ui_double_zoom_scale = mc_get_distance(arr_double_zoom_end_dot[0],arr_double_zoom_end_dot[1]) / mc_get_distance(arr_double_zoom_start_dot[0],arr_double_zoom_start_dot[1]);


        if (obj_mouse_pot.b_keyup) {
            // 双指中心
            var obj_origin = mc_get_double_zoom_origin({
                x: eve.touches[0].clientX,
                y: eve.touches[0].clientY
            },{
                x: eve.touches[1].clientX,
                y: eve.touches[1].clientY
            });

            obj_mouse_pot.b_keyup = false;
            obj_mouse_pot.ui_clientx = obj_origin.x;
            obj_mouse_pot.ui_clienty = obj_origin.y;
        }

        if (-1 === ui_before_zoom) {
            ui_before_zoom = ui_double_zoom_scale;
            if (1 > ui_before_zoom) {
                // 缩小
                mc_mod_sizedown(eve,10);
            } else {
                // 放大
                mc_mod_sizeup(eve,10);
            }
        } else {
            if (ui_before_zoom > ui_double_zoom_scale) {
                mc_mod_sizedown(eve,10);
            } else {
                mc_mod_sizeup(eve,10);
            }
            ui_before_zoom = ui_double_zoom_scale;
        }
        return false;
    }
    return true;
}

function mc_double_zoom_touchend() {
    if (b_double_zoom) {
        arr_double_zoom_start_dot = [];
        obj_double_finger_zoom = {};
        ui_before_zoom = -1;
        b_double_zoom = false;
        obj_mouse_pot.b_keyup = true;
        return false;
    }
    return true;
}

// 勾股
function mc_get_distance(p1, p2) {
    var x = p2.pageX - p1.pageX,
        y = p2.pageY - p1.pageY;

    return Math.sqrt((x * x) + (y * y));
}

// double zoom center
function mc_get_double_zoom_origin(obj_first,obj_second) {
    return {
        x: (obj_first.x + obj_second.x) / 2,
        y: (obj_first.y + obj_second.y) / 2
    };
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    判断当前元素是否存在指定class
 * 参数:
 *    @param { Promise<Object> } target 当前点击js元素
 *    @param { Promise<String> } str_calss 指定class
 *    @param { Promise<Object> } index 上层查找次数 2层既不再查找
 * 返回：
 *    @return { Promise<Object> }
 *      null 参数有误||没有指定class
 *      selectObject
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.05.26
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_judge_module_b_select(target,str_calss,index) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(target)) {
        return null;
    }
    if ($(target).hasClass(str_calss)) {
        return target;
    } else if ( 2 > index) {
        mc_judge_module_b_select(target.parentNode,++index);
    }
    return null;
}

// mousedown operate-----------
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    判断当前为选择模块还是拖拽操作
 *    CTRL：连续选中/拖拽复制  || UN CTRL：选中当前
 * 参数:
 *    @param { Promise<Object> } target 当前点击js元素
 *    @param { Promise<Object> } eve 鼠标事件
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      只选中Boolean / 拖拽复制 perate_param: 操作记录
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_select_or_copy_judge(target, eve) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(target)) {
        return false;
    }
    var even = eve || window.event;
    // judge select
    var b_select_target = false;

    if (even.ctrlKey) {
        // 编辑模式下不允许拖拽复制
        if (-1 !== target.className.split(/\s+/).indexOf("selected") && !b_progress_edit) {
            // draw copy--创建虚拟块、更新选中列表未新创建块
            // open connect-连线时 只进行选择
            if (b_connection) {
                return true;
            }
            return mc_draw_copy(target);
        }
        // click select--
        arr_select_mod.push($(target));
        b_select_target = true;
        // 点击选中返回
        box_return_new_value($("#mod_box_next"), arr_select_mod);
    } else {
        if (-1 === target.className.split(/\s+/).indexOf("selected")) {
            // select only one
            for (var idx = 0; idx < arr_select_mod.length; idx++) {
                var o_item = arr_select_mod[idx][0];

                mc_switch_mod_bg(o_item, false);
                o_item.classList.remove("selected");
            }
            arr_select_mod = [$(target)];
            b_select_target = true;
            // 点击选中返回
            mc_set_mouse_pot(mc_get_top_fun("mc_get_pnt",even,false,false,true));
            box_return_new_value($("#mod_box_next"), arr_select_mod);
        }
    }
    // 选中当前点击块
    if (b_select_target) {
        mc_switch_mod_bg(target, true);
        target.classList.add("selected");
    }
    // set zIndex
    mc_clear_zindex();
    mc_select_item_add_zindex(arr_select_mod);
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    拖拽复制
 * 参数:
 *    @param { Promise<Object> } target 当前点击js元素
 * 返回：
 *    @return { Promise<Object> }
 *      null 参数有误
 *      操作记录对象
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_draw_copy(target) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(target)) {
        return null;
    }
    // 拷贝当前复制列表
    var ary_copy_list_backup = arr_mod_selected_copy.slice();

    // 将复制列表改为选择列表
    mc_updata_selected_copy(arr_select_mod);
    var obj_copy = mc_copy_mod(target);
    var operate_param = obj_copy.operate_param;
    var arr_virtual_mod = document.getElementsByClassName("mc_virtual_mod");
    var ui_virtual_idx = 0;

    target = obj_copy.obj_virtual;
    // 复制列表改回拷贝列表
    mc_updata_selected_copy(ary_copy_list_backup);
    // 选中列表更新未拖拽复制列表
    arr_select_mod = [];
    while (ui_virtual_idx < arr_virtual_mod.length) {
        arr_select_mod.push($(arr_virtual_mod[ui_virtual_idx]));
        ui_virtual_idx++;
    }
    return operate_param;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    移动块数据记录、移动矩形设置
 * 参数:
 *    @param { Promise<Object> } eve 事件对象
 * 返回：
 *    @return { Promise<Array> }
 *      [] 参数有误
 *      移动实际块位置
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 *   2. 类型 : 添加
 *      作者 : 巫昭雯
 *      时间 : 2021.03.24
 *      内容 : 添加简易模式判断;
 ************************************************************************************************/
function mc_save_data_set_moveblk(eve) {
    if (0 === arr_select_mod.length) {
        return [];
    }
    ui_mov_grid_w = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));
    // 边界距离
    var ui_min_left = Math.pow(2, 32);
    var ui_min_top = Math.pow(2, 32);
    var ui_max_left = 0;
    var ui_max_top = 0;
    var arr_undo_pot = [];

    ary_selected_items = [];
    for (var idx = 0; idx < arr_select_mod.length; idx++) {
        var obj_js = arr_select_mod[idx][0];

        // 跳过锁定元素
        if (-1 !== obj_js.className.split(/\s+/).indexOf("mc_lock")) {
            continue;
        }
        var obj_msg = mc_get_child_pot_size(obj_js);
        var arr_pot = obj_msg.str_pot.split(",");
        var arr_size = obj_msg.str_size.split("X");
        var obj_transform_msg = mc_analysis_transform_msg(obj_js);
        // 获取处理过的数据
        var obj_val = mc_get_page_size_and_pos(obj_js, arr_pot);
        var ui_item_offsetl = obj_val.off_w;
        var ui_item_offsett = obj_val.off_h;

        var ui_min_l = ui_item_offsetl;
        var ui_max_l = "undefined" !== typeof obj_val.max_l ? obj_val.max_l : 0;
        var ui_min_t = ui_item_offsett;
        var ui_max_t = "undefined" !== typeof obj_val.max_t ? obj_val.max_t : 0;

        // 变换元素与外接矩形偏差
        var ui_transform_l = 0;
        var ui_transform_t = 0;

        arr_undo_pot.push([arr_pot[0], arr_pot[1]]);

        if (!obj_item_checkbox_easy_mode.get_dom_val()) {
            // 变换元素获取外接矩形偏移大小
            if (obj_transform_msg) {
                var ui_transform_offsetl = Number(obj_transform_msg[2]);
                var ui_transform_offsett = Number(obj_transform_msg[3]);

                // ui_min_l = ui_item_offsetl;
                ui_max_l = ui_min_l + Number(obj_transform_msg[0]);
                // ui_min_t = ui_item_offsett;
                ui_max_t = ui_min_t + Number(obj_transform_msg[1]);

                ui_transform_l = Math.round(ui_transform_offsetl);
                ui_transform_t = Math.round(ui_transform_offsett);
            } else {
                // ui_min_l = ui_item_offsetl;
                ui_max_l = ui_min_l + Number(arr_size[0]) * ui_mov_grid_w;
                // ui_min_t = ui_item_offsett;
                ui_max_t = ui_min_t + Number(arr_size[1]) * ui_mov_grid_w;
            }
        }


        if (ui_min_left > ui_min_l) {
            ui_min_left = ui_min_l;
        }
        if (ui_max_left < ui_max_l) {
            ui_max_left = ui_max_l;
        }
        if (ui_min_top > ui_min_t) {
            ui_min_top = ui_min_t;
        }
        if (ui_max_top < ui_max_t) {
            ui_max_top = ui_max_t;
        }
        // ary_selected_items.push({BLK: obj_js,X: ui_item_offsetl + ui_transform_l,Y: ui_item_offsett + ui_transform_t,tsfX: ui_transform_l / ui_mov_grid_w,tsfY: ui_transform_t / ui_mov_grid_w});
        ary_selected_items.push({ BLK: obj_js, X: ui_item_offsetl + ui_transform_l, Y: ui_item_offsett + ui_transform_t });
    }
    if (0 === this.ary_selected_items.length) {
        return false;
    }
    // 拖拽开始前鼠标位置
    obj_base_pnt = mc_get_top_fun("mc_get_pnt",eve,false,false,true);
    var obj_blk_move = document.getElementById("mc_blk_move");
    var obj_box = document.getElementById("mc_box_canvasbg");
    var ui_blk_mov_w = ui_max_left - ui_min_left;
    var ui_blk_mov_h = ui_max_top - ui_min_top;

    obj_mov = { OBJ: obj_blk_move, X: ui_min_left, Y: ui_min_top, W: ui_blk_mov_w, H: ui_blk_mov_h };
    obj_draw_boundary = { X: obj_box.offsetWidth - ui_blk_mov_w, Y: obj_box.offsetHeight - ui_blk_mov_h };
    obj_blk_move.style.width = ui_blk_mov_w + "px";
    obj_blk_move.style.height = ui_blk_mov_h + "px";
    obj_blk_move.style.left = ui_min_left + "px";
    obj_blk_move.style.top = ui_min_top + "px";
    obj_blk_move.style.display = "block";
    // obj_blk_move.style.display = "flex";

    return arr_undo_pot;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取模块offset值; 和模块的最大最小 left，top值; 页面数值;
 * 参数:
 *    @param { Promise<Object> } obj_js 模块
 *    @param { Promise<String> } arr_pot 原始位置值字符串
 * 返回:
 *    @returns { Promise<Object> } 简易模式下返回位置值 + left,top边界值 || 返回模块位置值
 * 例子:
 *    NA
 * 备注:
 *     返回参数备注 {
 *          off_w: offset width,
 *          off_h: offset height,
 *          max_l: max left,
 *          max_t: max top
 *      }
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-03-24
 *       内容 : 所有代码
************************************************************************************************/
function mc_get_page_size_and_pos(obj_js, arr_pot) {
    if (obj_item_checkbox_easy_mode.get_dom_val()) {
        var ui_item_offsetl = Number(obj_js.style.left.split("px")[0]);
        var ui_item_offsett = Number(obj_js.style.top.split("px")[0]);
        var ui_easy_mode_div_wh = ui_easy_mode_size * ui_mov_grid_w;

        return {
            off_w: ui_item_offsetl,
            off_h: ui_item_offsett,
            max_l: ui_item_offsetl + ui_easy_mode_div_wh,
            max_t: ui_item_offsett + ui_easy_mode_div_wh
        };
    }

    return {
        off_w: Number(arr_pot[0]) * ui_mov_grid_w,
        off_h: Number(arr_pot[1]) * ui_mov_grid_w
    };
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取整体模块信息 设置黏合开关
 * 参数:
 *    无
 * 返回：
 *    @return { Promise<Array> }
 *      [未选中模块整体Lmin,Tmin,Lmax+Wr,Lmax+Hr]
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_modulemsg_set_adhesions() {
    var arr_no_select_msg = [];

    // 未选中模块整体Lmin,Tmin,Lmax+Wr,Lmax+Hr
    if (document.getElementsByClassName("mc_mod").length !== arr_select_mod.length) {
        // 直接获取选中数据更新
        arr_no_select_msg = get_module_boundary(false, true);
    } else {
        arr_no_select_msg = false;
    }

    // 黏合
    if (b_open_adhesions) {
        // 开启延时黏合
        fn_draw_settimeout = setTimeout(function () {
            b_settimeout_adhesions = true;
        }, 500);
    }
    return arr_no_select_msg;
}

// mousemove 黏合处理 :移动矩形偏移------
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    黏合处理 :移动矩形偏移
 * 参数:
 *    @param { Promise<Number> } ui_x
 *    @param { Promise<Number> } ui_y
 * 返回：
 *    @return { Promise<Object> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_mov_set_adhesions_return_data(ui_x, ui_y) {
    if (0 === ary_selected_items.length) {
        return false;
    }
    if ("[object Number]" !== Object.prototype.toString.call(ui_x) || "[object Number]" !== Object.prototype.toString.call(ui_y)) {
        return false;
    }
    var ui_box_sacle = ui_mod_box_scale / 100;
    var ui_adhesions_offset = 20 / ui_box_sacle;
    // 黏合范围对象 四周20px
    var obj_adhesions_scope = {
        ui_l: ui_x - ui_adhesions_offset,
        ui_r: ui_x + obj_mov.W + ui_adhesions_offset,
        ui_t: ui_y - ui_adhesions_offset,
        ui_b: ui_y + obj_mov.H + ui_adhesions_offset
    };

    mc_mod_adhesions_match(obj_adhesions_scope, function (arr_adhesions_date) {
        if (0 === arr_adhesions_date.length) {
            return;
        }
        var str_type = arr_adhesions_date[0];
        var ui_offset = arr_adhesions_date[1];

        if ("left" === str_type) {
            str_type = "left";
            ui_offset -= ui_x;
        }
        if ("right" === str_type) {
            str_type = "left";
            ui_offset = ui_offset - ui_x - obj_mov.W;
        }
        if ("top" === str_type) {
            str_type = "top";
            ui_offset -= ui_y;
        }
        if ("bto" === str_type) {
            str_type = "top";
            ui_offset = ui_offset - ui_y - obj_mov.H;
        }
        mc_mov_blk_adhesions(str_type, ui_offset, ui_adhesions_offset);
    });
    return true;
}

// mouseup----------------------------
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    拖拽复制模块设置 （移动距离 移动格子数 操作记录）
 * 参数:
 *    @param { Promise<Number> } ui_x 移动距离X
 *    @param { Promise<Number> } ui_y 移动距离Y
 *    @param { Promise<Number> } u_x 移动格子数
 *    @param { Promise<Number> } u_y 移动格子数
 * 返回：
 *    @return { Promise<Object> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_set_mov_copy_blk(ui_x, ui_y, u_x, u_y) {
    // 重置选中元素为当前新元素
    // arr_select_mod = [];
    var operate_param = obj_mov_operate_param.operate_param;

    for (var idx = 0; idx < ary_selected_items.length; idx++) {
        var obj_mod = ary_selected_items[idx];
        var obj_js = obj_mod.BLK;
        var child_list = obj_js.childNodes;

        // obj_mod.BLK.style.display = "block";
        obj_js.style.left = (obj_mod.X + ui_x) + "px";
        obj_js.style.top = (obj_mod.Y + ui_y) + "px";

        // 除锁定元素 显示其余子元素
        for (var i = 0; i < child_list.length - 1; i++) {
            child_list[i].style.display = "block";
        }
        obj_js.classList.remove("mc_virtual_mod");
        // 更新显示及保存数据
        update_show_and_data(obj_js, u_x, u_y);
        operate_param.undo = mc_transform_id_data(arr_select_mod);
        operate_param.redo = mc_get_create_module_msg(arr_select_mod);
    }
    return true;
}


// other-----------------------------
// 区分移动端|PC端 事件类型
function mc_judge_event_type() {
    var obj = {};

    if (b_istouch) {
        obj.triggerEvenDown = "mousedown";
        obj.triggerEvenMove = "mousemove";
        obj.triggerEvenUp = "mouseup";
    } else {
        obj.triggerEvenDown = "touchstart";
        obj.triggerEvenMove = "touchmove";
        obj.triggerEvenUp = "touchend";
    }
    return obj;
}

// 框选范围判断
function mc_select_boundary_judge(str_downtarget_id,eventDown) {
    var b_bourder_trigger = "mc_box_canvasbg" === str_downtarget_id || "mc_edit_border" === str_downtarget_id;
    var b_lock_trigger = -1 !== eventDown.target.className.indexOf("mc_lock")
        || -1 !== eventDown.target.offsetParent.className.indexOf("mc_lock") || -1 !== eventDown.target.offsetParent.offsetParent.className.indexOf("mc_lock");

    return [b_bourder_trigger,b_lock_trigger];
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    更新模块位置显示信息、更新数据
 * 参数:
 *    @param { Promise<Object> } obj_js
 *    @param { Promise<Number> } ui_x 实际前进后退格子数X
 *    @param { Promise<Number> } ui_y 实际前进后退格子数Y
 *    @param { Promise<Object> } obj_mod 移动框数据对象
 * 返回：
 *    @return { Promise<Object> }
 *      false 参数有误
 *      true 设置成功 || redo数组 可为空
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function update_show_and_data(obj_js, ui_x, ui_y, obj_mod) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_js)) {
        return false;
    }
    if ("[object Number]" !== Object.prototype.toString.call(ui_x) || "[object Number]" !== Object.prototype.toString.call(ui_y)) {
        return false;
    }

    var obj_msg = mc_get_child_pot_size(obj_js);
    var obj_pot = obj_msg.o_pot;
    var str_before_pot_txt = obj_msg.str_pot;
    var arr_before_pot = str_before_pot_txt.split(",");
    var str_txt = mc_easy_mode_get_pos_val(obj_mod, obj_msg, (Number(arr_before_pot[0]) + ui_x) + "," + (Number(arr_before_pot[1]) + ui_y) );

    if (str_before_pot_txt === str_txt) {
        return false;
    }

    obj_pot.innerText = str_txt;
    mc_update_module_msg(obj_js.id, str_txt, false);
    // move redo module pot
    if ("[object Object]" === Object.prototype.toString.call(obj_mod)) {
        return [Number(arr_before_pot[0]) + ui_x, (Number(arr_before_pot[1]) + ui_y)];
    }
    return true;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    简易模式下: 获取模块的位置值 (模块移动之后); 参数与原函数 参数一致;
 * 参数:
 *    @param { Promise<Object> } obj_mod 模块对象
 *    @param { Promise<Object> } obj_msg 保存的数据; 与函数参数数据一致
 *    @param { Promise<String> } old_val 原始模式下的位置值字符串
 * 返回:
 *    @returns { Promise<String> } 简易模式下的移动位置 || 原始位置
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2021-03-24
 *       内容 : 所有代码
************************************************************************************************/
function mc_easy_mode_get_pos_val(obj_mod, obj_msg, old_val) {
    if (obj_item_checkbox_easy_mode.get_dom_val() && obj_mod) {
        var ui_size = obj_msg.str_size.split("X");
        var ui_div_wh = ui_easy_mode_size * ui_mov_grid_w;
        var ui_off_l = Number(obj_mod.BLK.style.left.split("px")[0]);
        var ui_off_t = Number(obj_mod.BLK.style.top.split("px")[0]);
        var str_txt = (mc_util_round(ui_off_l / ui_div_wh) * ui_size[0]) + "," + (mc_util_round(ui_off_t / ui_div_wh) * ui_size[1]);

        return str_txt;
    }

    return old_val;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取移动格子数
 * 参数:
 *    @param { Promise<Number> } i_offset_x 移动距离X
 *    @param { Promise<Number> } i_offset_y 移动距离Y
 *    @param { Promise<Boolean> } b_computer_gridw 是否计算格子宽度
 * 返回：
 *    @return { Promise<Object> }
 *      {ui_x: ui_x,ui_y: ui_y};
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function get_move_grid(i_offset_x, i_offset_y, b_computer_gridw) {
    // i_offset_x /= ui_mov_grid_w;
    // i_offset_y /= ui_mov_grid_w;
    // if (b_computer_gridw) {
    //     i_offset_x *= ui_mov_grid_w;
    //     i_offset_y *= ui_mov_grid_w;
    // }
    // return {ui_x: i_offset_x,ui_y: i_offset_y};
    // 移动格子数
    var ui_x = Math.round(i_offset_x / ui_mov_grid_w);
    var ui_y = Math.round(i_offset_y / ui_mov_grid_w);

    // 简易模式处理
    if (obj_item_checkbox_easy_mode.get_dom_val()) {
        ui_x = mc_util_round(ui_x / ui_easy_mode_size) * ui_easy_mode_size;
        ui_y = mc_util_round(ui_y / ui_easy_mode_size) * ui_easy_mode_size;
    }
    if (b_computer_gridw) {
        ui_x *= ui_mov_grid_w;
        ui_y *= ui_mov_grid_w;
    }
    return { ui_x: ui_x, ui_y: ui_y };
}

// optimize draw end -------------------------
/************************************************************************************************
* 类型:
*    函数
* 功能:
*    初始化移动盒子和偏移宽高
* 参数:
*    无
* 返回：
*   @return { Promise<Boolean> }
*     true 设置成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2021.02.09
*      内容 : 所有代码
************************************************************************************************/
function init_mc_move_layer() {
    var obj_mod_box = document.getElementById("mod_box_next");
    var obj_move_box = document.getElementById("mc_move_layer");

    if (obj_mod_box && obj_move_box) {
        obj_move_box.style.left = obj_mod_box.offsetLeft + "px";
        obj_move_box.style.top = obj_mod_box.offsetTop + "px";
        obj_move_box.style.width = obj_mod_box.offsetWidth + "px";
        obj_move_box.style.height = obj_mod_box.offsetHeight + "px";
    }
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    设置移动盒子偏移 简易模式下扣除栅格大小偏差
* 参数:
*    @param { Promise<Number> } ui_l
*    @param { Promise<Number> } ui_t
* 返回：
*   @return { Promise<Boolean> }
*     false 参数有误
*     true 设置成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2021.02.09
*      内容 : 所有代码
************************************************************************************************/
function set_mc_move_layer_offset(ui_l, ui_t) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_l) || "[object Number]" !== Object.prototype.toString.call(ui_t)) {
        return false;
    }
    var obj_mov_box = document.getElementById("mc_move_layer");

    if (!obj_mov_box) {
        return false;
    }
    obj_mov_box.style.left = ui_l + "px";
    obj_mov_box.style.top = ui_t + "px";
    return true;
}

/*******************************模组拖拽黏合相关函数***********************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    选中模组移动黏合匹配方向
 * 参数:
 *    @param { Promise<Object> } obj_scope 选中模组边界元素黏合距离对象
 *    @param { Promise<Function> } fun_callback 传入回调函数 不可为空 若匹配参数为返回数组数据
 * 返回：
 *    @return { Promise<Function> }
 *      fun_callback([]) 参数有误/不匹配
 *      fun_callback([偏移方向:string, 偏移距离:number])
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.12
 *      内容 : 所有代码
 ************************************************************************************************/
// eslint-disable-next-line complexity
function mc_mod_adhesions_match(obj_scope, fun_callback) {
    if ("object" !== typeof obj_scope || "function" !== typeof fun_callback) {
        return fun_callback([]);
    }
    var ui_l = obj_scope.ui_l;
    var ui_r = obj_scope.ui_r;
    var ui_t = obj_scope.ui_t;
    var ui_b = obj_scope.ui_b;
    var arr_mod = document.getElementsByClassName("mc_mod");
    var ui_box_sacle = ui_mod_box_scale / 100;
    var ui_adhesions_offset = 20 / ui_box_sacle;

    for (var idx = 0; idx < arr_mod.length; idx++) {
        var o_item = arr_mod[idx];

        // 非选中对象进行距离比对
        if (-1 === o_item.className.indexOf("selected")) {
            var arr_size = mc_get_optsize_msg(o_item, true);
            var arr_pot = mc_get_optsize_msg(o_item);
            var ui_item_l = arr_pot[0];
            var ui_item_t = arr_pot[1];
            var ui_item_maxl = ui_item_l + arr_size[0];
            var ui_item_maxt = ui_item_t + arr_size[1];

            if (ui_adhesions_offset > Math.abs(ui_b - ui_item_t) && ((ui_item_l >= ui_l && ui_item_l <= ui_r) || (ui_item_maxl >= ui_l && ui_item_maxl <= ui_r))) {
                return fun_callback(["bto", ui_item_t ]);
            }
            if (ui_adhesions_offset > Math.abs(ui_t - ui_item_maxt) && ((ui_item_l >= ui_l && ui_item_l <= ui_r) || (ui_item_maxl >= ui_l && ui_item_maxl <= ui_r))) {
                return fun_callback(["top", ui_item_maxt]);
            }
            if (ui_adhesions_offset > Math.abs(ui_item_maxl - ui_l) && ((ui_item_maxt <= ui_b && ui_item_maxt >= ui_t) || (ui_item_t <= ui_b && ui_item_t >= ui_t))) {
                return fun_callback(["left", ui_item_maxl]);
            }
            if (ui_adhesions_offset > Math.abs(ui_item_l - ui_r) && ((ui_item_maxt <= ui_b && ui_item_maxt >= ui_t) || (ui_item_t <= ui_b && ui_item_t >= ui_t))) {
                return fun_callback(["right", ui_item_l ]);
            }
        }
    }
    return fun_callback([]);
}


// 移动矩形黏合偏移 当前黏合偏移类型/黏合量/黏合范围
function mc_mov_blk_adhesions(str_type, ui_offset) {
    if ("[object String]" !== Object.prototype.toString.call(str_type) || "[object Number]" !== Object.prototype.toString.call(ui_offset)) {
        return false;
    }
    var obj_blk_mov = obj_mov.OBJ;

    if ("top" === str_type) {
        obj_blk_mov.style.top = obj_blk_mov.offsetTop + ui_offset + "px";
    }
    if ("left" === str_type) {
        obj_blk_mov.style.left = obj_blk_mov.offsetLeft + ui_offset + "px";
    }
    return true;
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    是否开启黏合
 * 参数:
 *    @param { Promise<Boolean> } b_start true开启
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.12
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_mod_adhesions_switch(b_start) {
    if ("[object Boolean]" !== Object.prototype.toString.call(b_start)) {
        return false;
    }
    b_open_adhesions = b_start;
    b_settimeout_adhesions = b_start;
    if (!b_start && fn_draw_settimeout) {
        clearInterval(fn_draw_settimeout);
    }
    return true;
}


/*******************************document事件*****************************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    键盘事件 快捷键操作模组
 * 功能详解:
 *    复制 : CTRL+C
 *    粘贴 : CTRL+V
 *    全选 : CTRT+A
 *    打印日志 : CTRT+L
 *    取消选中模块 : ESC
 *    删除选中模块 : DELETE
 *    上下左右控制选中模块移动
 * 参数:
 *    @param { Promise<Object> } eve 事件对象
 * 返回：
 *    @return { Promise<Boolean> }
 *      true 设置成功
 *      false 不符合触发要求
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.14
 *      内容 : 所有代码
 ************************************************************************************************/
document.onkeydown = function (eve) {
    var e = eve || window.event;
    var obj_focus_pot = document.activeElement;

    // 焦点位置 在输入框不触发/控件
    if ("input" === obj_focus_pot.tagName || obj_focus_pot.getAttribute("control_type")) {
        return true;
    }

    // ctrl + A 全选
    if (e.ctrlKey && 65 === e.keyCode) {
        select_all_operation();
        return true;
    }

    if (edit_state_disable()) {
        return true;
    }

    // ctrl + l
    if (e.ctrlKey && 76 === e.keyCode && g_obj_save_log) {
        var ary_log_list = g_obj_save_log.get_log_txt();

        if (0 < ary_log_list.length) {
            var str_val = "";

            for (var index = 0; index < ary_log_list.length; index++) {
                var value = ary_log_list[index];

                if (value) {
                    str_val += value + "<br/>";
                }
            }
            var str_html = "<div style=\"height:100%;overflow: auto;\">" + str_val + "</div>";

            layer.alert(str_html);
        }
    }

    // delete 删除
    // if (46 === e.keyCode) {
    //     mc_delete_mod();
    //     mc_close_menu();
    //     return true;
    // }

    // esc 取消选择
    if (27 === e.keyCode) {
        mc_mod_uncheck(arr_select_mod, true);
        // 关闭选择菜单栏
        mc_close_menu();
        return true;
    }

    // 上下左右控制模组移动
    mc_module_keyboard_move(e);
    return true;

    // 编辑状态下禁止操作快捷键
    function edit_state_disable() {
        if (b_progress_edit) {
            return true;
        }

        // ctrl + c
        if (e.ctrlKey && 67 === e.keyCode ) {
            mc_lang_copy_module();
            return true;
        }

        // ctrl + v
        if (e.ctrlKey && 86 === e.keyCode ) {
            mc_set_paset();
            return true;
        }

        // ctrl + z回撤
        if (e.ctrlKey && 90 === e.keyCode) {
            mc_lang_undo_module();
            return true;
        }

        // ctrl + y 重做
        if (e.ctrlKey && 89 === e.keyCode) {
            mc_lang_redo_module();
            return true;
        }

        // delete 删除
        if (!e.ctrlKey && 46 === e.keyCode) {
            mc_delete_mod();
            mc_close_menu();
            return true;
        }
        return false;
    }
};

document.onkeyup = function () {
    obj_mouse_pot.b_keyup = true;
};

// 全选操作
function select_all_operation() {
    var str_lang_add = "MC_LANG_POPOUT_ADD_MOD";

    if (!b_create_grid) {
        str_lang_add = "MC_LANG_POPOUT_NO_ADD_BOX";
    }

    var b_res = false;

    if (0 === $(".mc_mod").length) {
        mc_get_top_fun("mc_alert_popout", str_lang_add, "alert_get_focus");
    } else {
        if ($(".selected").length !== $(".mc_mod").length) {
            var obj_list = document.getElementsByClassName("mc_mod");

            for (var idx = 0; idx < obj_list.length; idx++) {
                var o_item = obj_list[idx];

                mc_switch_mod_bg(o_item, true);
                o_item.classList.add("selected");
            }
            arr_select_mod = set_arr_select_mod(false);
            if (0 !== arr_select_mod.length) {
                mc_select_item_add_zindex(arr_select_mod);
                box_return_new_value($("#mod_box_next"), arr_select_mod);
            }
        }
        b_res = true;
    }
    clearBubble();

    return b_res;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    选中元素键盘移动操作
 * 参数:
 *     @param { Promise<Object> } eve 事件对象
 * 返回：
 *    @return { Promise<Boolean> }
 *      true 设置成功
 *      false 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.14
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_module_keyboard_move(eve) {
    var e = eve || window.event;

    if (0 === arr_select_mod.length || 37 > e.keyCode || 40 < e.keyCode) {
        return false;
    }
    // 滚动条所在元素 传入id元素
    var obj_parent = $("#mod_box_next").parent();
    // 过滤锁定元素
    var ary_select_mod = $.extend(true, [], arr_select_mod);
    // 移动参数
    var obj_move_params = {
        // 框选边界元素距离
        ui_boundary_left: Math.pow(2, 32),
        ui_boundary_top: Math.pow(2, 32),
        ui_boundary_right: 0,
        ui_boundary_bot: 0,
        // 框选边界元素
        o_max_left_item: "",
        o_max_top_item: "",
        o_max_right_item: "",
        o_max_bot_item: "",
        // 边界元素偏移/宽度计算
        ui_max_left_l: 0,
        ui_max_top_t: 0,
        ui_max_right_w: 0,
        ui_max_bot_h: 0,
        // canvas宽高
        ui_canvas_w: $("#mc_box_canvasbg").width(),
        ui_canvas_h: $("#mc_box_canvasbg").height(),
        // 当前格子宽度
        i_grid_width: parseInt($("#mod_box_next").attr("grid_w"), 10),
        // mod_box盒子对象 显示区域
        o_mod_box: $(".mc_mod_box"),
        ui_keycode: e.keyCode,
        // 滚动条宽度
        ui_scrollbar_width: 0,
        // 滚动条滚动距离
        ui_scroll_l: obj_parent.scrollLeft(),
        ui_scroll_t: obj_parent.scrollTop(),
        // 键盘操作移动边界距离
        arr_select_mod: ary_select_mod
    };

    // 获取边界元素边界位置
    obj_move_params = get_boundary_obj(ary_select_mod, obj_move_params);
    // 应用程序下计算滚动条宽度
    if (mc_nwjs_check_support()) {
        var str_id = obj_parent.attr("id");

        obj_move_params.ui_scrollbar_width = mc_get_scrollbar_width(str_id);
    }

    // 键盘操作框选元素移动
    select_mod_keydown(obj_move_params);

    // 返回框选数组
    // box_return_new_value(obj_move_params.o_mod_box, arr_select_mod);
    clearBubble();
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    粘贴设置
 * 参数:
 *     NA
 * 返回：
 *    NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.14
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_set_paset() {
    if (0 >= arr_mod_selected_copy.length) {
        if (b_create_grid) {
            mc_get_top_fun("mc_alert_popout", "MC_LANG_POPOUT_COPU_MOD", "alert_get_focus");
        } else {
            mc_get_top_fun("mc_alert_popout", "MC_LANG_POPOUT_NO_COPY_RECVCARD", "alert_get_focus");
        }
    }
    var obj_copy = mc_copy_mod();

    // 更改当前选中模组为新增
    mc_mod_uncheck(arr_select_mod);

    if (0 !== $(".selected").length) {
        arr_select_mod = [];
        var ui_select_idx = 0;

        while (ui_select_idx < $(".selected").length) {
            var obj_jq = $(".selected").eq(ui_select_idx);

            arr_select_mod.push(obj_jq);
            mc_switch_mod_bg(obj_jq[0], true);
            ui_select_idx++;
        }
    }
    // 更改层叠性
    // mc_clear_zindex();
    mc_select_item_add_zindex(arr_select_mod);

    var operate_param = obj_copy.operate_param;

    operate_param.undo = mc_transform_id_data(arr_select_mod);
    operate_param.redo = mc_get_create_module_msg(arr_select_mod);
    // mc_layout_operate("curd",operate_param);

    // // 简易模式
    // if (obj_item_checkbox_easy_mode.get_dom_val()) {
    //     set_easy_mode(true);
    // }
    if ("function" === typeof mc_update_module_size) {
        mc_update_module_size();
    }
    // 返回选中
    box_return_new_value($("#mod_box_next"), arr_select_mod);
    mc_layout_operate("curd", operate_param);
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    粘贴_添加模组
* 参数:
*    @param { Promise<Object> } obj 当前操作对象 创建虚拟模组时传入
* 返回：
*    @return { Promise<Object> }
*    obj_virtual 当前操作的虚拟模组
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.6.11
*      内容 : 所有代码
************************************************************************************************/
function mc_copy_mod(obj) {
    var obj_box = get_obj_box();

    if (!obj_box) {
        return false;
    }
    var ui_offset = 5;
    var str_html = "";
    var b_easy_mode = obj_item_checkbox_easy_mode.get_dom_val();
    var str_mod_class = "mc_mod selected unset_module";
    var obj_virtual = obj;
    var b_add_virtual = false;

    // 记录添加操作
    var operate_param = new mc_layout_operate_format_data();

    operate_param.undo = mc_transform_id_data(arr_select_mod);
    operate_param.update_select_list.undo = mc_transform_id_data(arr_select_mod);
    if (obj) {
        ui_offset = 0;
        str_mod_class += " mc_virtual_mod";
        b_add_virtual = true;
    }
    for (var i = 0; i < arr_mod_selected_copy.length; i++) {
        var obj_jq = arr_mod_selected_copy[i];

        if (!document.getElementById(obj_jq.attr("id"))) {
            continue;
        }
        var obj_js = obj_jq[0];
        var obj_child = mc_get_child_pot_size(obj_js);
        var arr_size = obj_child.str_size.split("X");
        var arr_pot = obj_child.str_pot.split(",");
        var ui_grid = parseInt(document.getElementById("mod_box_next").getAttribute("grid_w"), 10);
        var arr_transform = mc_analysis_transform_msg(obj_js, "all");
        var str_module_name = obj_js.getAttribute("mod_id");
        var str_trans_easy_mode = obj_js.getAttribute("str_trans");
        var str_mod_id = "mod" + mc_get_id();

        arr_transform = arr_transform ? [arr_transform[2][0], arr_transform[2][1], arr_transform[1], arr_transform[3],arr_transform[4]] : [];
        var obj_param = {
            width: Number(arr_size[0]),
            height: Number(arr_size[1]),
            left: Number(arr_pot[0]) + ui_offset,
            top: Number(arr_pot[1]) + ui_offset,
            module_class: str_mod_class,
            module_style: "",
            center_hub_val: "?",
            module_id: str_module_name,
            module_list_idx: "?",
            module_card_idx: "",
            transform_msg: arr_transform,
            // ctrlchip_name: mc_get_appoint_obj(obj_jq,"chip_name").innerText,
            // module_show_name: g_obj_side_show_name.get_name("BOX",str_module_name),
            attr: ""
        };

        obj_param.module_style = "width:" + obj_param.width * ui_grid + "px;height:" + obj_param.height * ui_grid + "px;left:" + obj_param.left * ui_grid + "px;top:" + obj_param.top * ui_grid + "px;";
        if (b_easy_mode && str_trans_easy_mode) {
            obj_param.attr = "str_trans=" + str_trans_easy_mode;
        }
        if (obj === obj_js) {
            obj_virtual = str_mod_id;
        }
        if (b_create_grid) {
            obj_param.module_show_name = g_obj_side_show_name.get_name("MOD", str_module_name);
        } else {
            var obj_chip = mc_get_appoint_obj(obj_jq, "chip_name");

            if (obj_chip) {
                obj_param.ctrlchip_name = obj_chip.innerText;
            }
            obj_param.module_show_name = g_obj_side_show_name.get_name("BOX", str_module_name);
        }
        str_html += obj_box.get_module_html_str(obj_param, {}, str_mod_id).str_html;
    }
    obj_box.add_module_html(str_html, {}, b_add_virtual);
    if (obj_virtual) {
        // 拖拽复制：取消原先选中队列
        mc_mod_uncheck(arr_select_mod);
        obj_virtual = document.getElementById(obj_virtual);
    }
    // 更新整体模块显示信息
    update_module_msg_txt(get_module_boundary(true), true);
    // 简易模式
    if (b_easy_mode) {
        set_easy_mode(true);
    }
    return { "obj_virtual": obj_virtual, "operate_param": operate_param };
}

/*******************************键盘控制移动*****************************************************/
// 键盘操作模块移动 延时更新连线、模块整体信息、记录操作
var mc_keyboard_operate_move_timer = null;
var obj_keyboard_operate_move_param = null;

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    框选元素键盘操作
 * 参数:
 *     @param { Promise<Array> } params 移动参数对象
 * 返回：
 *    @return { Promise<Boolean> }
 *      true 设置成功
 *      false 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.03.03
 *      内容 : 所有代码
 ************************************************************************************************/
function select_mod_keydown(params) {
    if (!params) {
        return false;
    }
    var obj_params = {
        str_direction: "",
        arr_mod: params.arr_select_mod,
        ui_grid_width: params.i_grid_width,
        // 边界元素、边界位置
        params: params
    };

    switch (params.ui_keycode) {
    // move up
    case 38:
        if (0 < params.ui_max_top_t) {
            obj_params.str_direction = "up";
            mc_mod_keydown_move(obj_params);
        }
        break;
        // move down
    case 40:
        var ui_max_down = params.ui_canvas_h - params.ui_max_bot_h;
        // var ui_top_item_h = mc_get_optsize_msg(params.o_max_top_item,true)[1];
        var ui_min_down = params.ui_canvas_h - params.o_max_top_item.offsetHeight - params.ui_boundary_bot + params.ui_boundary_top;

        if (ui_max_down > params.ui_boundary_top && params.ui_max_top_t < ui_min_down) {
            obj_params.str_direction = "down";
            mc_mod_keydown_move(obj_params);
        }
        break;
        // left shift
    case 37:
        if (0 < params.ui_max_left_l) {
            obj_params.str_direction = "left";
            mc_mod_keydown_move(obj_params);
        }
        break;
        // right shift
    case 39:
        var ui_max_right = params.ui_canvas_w - params.ui_max_right_w;
        // var ui_left_item_w = mc_get_optsize_msg(params.o_max_left_item,true)[0];
        var ui_min_right = params.ui_canvas_w - params.o_max_left_item.offsetWidth - params.ui_boundary_right + params.ui_boundary_left;

        if (ui_max_right > params.ui_boundary_right && params.ui_max_left_l < ui_min_right) {
            obj_params.str_direction = "right";
            mc_mod_keydown_move(obj_params);
        }
        break;
    default:
    }

    // 边界处理滚动条
    select_mod_keydown_slider(params);
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    框选元素键盘操作 - 移动元素
 * 参数:
 *     @param { Promise<Array> } params 移动参数对象
 * 返回：
 *    无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.5.20
 *      内容 : 所有代码
 *   2. 类型 : 添加
 *      作者 : 巫昭雯
 *      时间 : 2020.11.28
 *      内容 : 简易模式下的键盘移动事件; 移动步进值为统一设置大小；显示的位置步进值为原始模块大小;
 ************************************************************************************************/
function mc_mod_keydown_move(params) {
    mc_show_hide_line_svg("none");
    var b_save = false;

    if (!obj_keyboard_operate_move_param) {
        // 构造撤销重做参数 键盘移动
        obj_keyboard_operate_move_param = new mc_layout_operate_format_data();
        obj_keyboard_operate_move_param.obj_list = mc_transform_id_data(arr_select_mod);
        b_save = true;
    }

    // 模块未移动前位置格子数
    var arr_undo_pot = [];
    var arr_redo_pot = [];
    var arr_mod = params.arr_mod;
    var str_direction = params.str_direction;
    var i_grid_width = params.ui_grid_width;
    // 当前移动方向距离
    var ui_move_vertical = 0;
    var ui_move_level = 0;

    if (obj_item_checkbox_easy_mode.get_dom_val()) {
        i_grid_width *= ui_easy_mode_size;
    }

    for (var idx_mod = 0; idx_mod < arr_mod.length; idx_mod++) {
        var o_mod = arr_mod[idx_mod][0];
        var ui_position = -1;
        var ui_mod_top = o_mod.offsetTop;
        var ui_mod_left = o_mod.offsetLeft;
        var b_vertical = false;
        var b_level = false;

        if ("up" === str_direction) {
            ui_position = ui_mod_top - i_grid_width;
            ui_move_vertical = -i_grid_width;
            b_vertical = true;
        }
        if ("down" === str_direction) {
            ui_position = ui_mod_top + i_grid_width;
            ui_move_vertical = i_grid_width;
            b_vertical = true;
        }
        if ("left" === str_direction) {
            ui_position = ui_mod_left - i_grid_width;
            ui_move_level = -i_grid_width;
            b_level = true;
        }
        if ("right" === str_direction) {
            ui_position = ui_mod_left + i_grid_width;
            ui_move_level = i_grid_width;
            b_level = true;
        }
        if (-1 !== ui_position) {
            var obj_msg = mc_get_child_pot_size(o_mod);
            var arr_pot = obj_msg.str_pot.split(",");
            var ui_x = arr_pot[0];
            var ui_y = arr_pot[1];

            if (b_save) {
                arr_undo_pot.push([ui_x, ui_y]);
            }

            if (b_vertical) {
                o_mod.style.top = ui_position + "px";
                ui_y = parseInt(ui_position / parseFloat(i_grid_width), 10);

                if (obj_item_checkbox_easy_mode.get_dom_val()) {
                    ui_y *= Number(o_mod.getAttribute("mod_hg"));
                }
            }

            if (b_level) {
                o_mod.style.left = ui_position + "px";
                ui_x = parseInt(ui_position / parseFloat(i_grid_width), 10);

                if (obj_item_checkbox_easy_mode.get_dom_val()) {
                    ui_x *= Number(o_mod.getAttribute("mod_wg"));
                }
            }


            if (obj_item_checkbox_easy_mode.get_dom_val()) {
                update_mod_pot(o_mod, ui_x, ui_y, false);
            } else {
                update_mod_pot(o_mod, ui_x, ui_y, true);
            }
            arr_redo_pot.push([ui_x, ui_y]);
        }
    }
    if (0 !== arr_undo_pot.length) {
        obj_keyboard_operate_move_param.undo = arr_undo_pot;
    }
    obj_keyboard_operate_move_param.redo = arr_redo_pot;

    if (mc_keyboard_operate_move_timer) {
        clearTimeout(mc_keyboard_operate_move_timer);
    }

    mc_keyboard_operate_move_timer = setTimeout(function () {
        var obj_boundary_msg = params.params;

        if (obj_boundary_msg) {
            var arr_no_select_msg = [];
            // 模块整体信息Lmin,Tmin,Lmax+Wr,Tmax+Hr
            var arr_module_msg = [Number(obj_boundary_msg.ui_max_left_l) + ui_move_level, Number(obj_boundary_msg.ui_max_top_t) + ui_move_vertical, Number(obj_boundary_msg.ui_boundary_right) + Number(obj_boundary_msg.ui_max_right_w) + ui_move_level, Number(obj_boundary_msg.ui_boundary_bot) + ui_move_vertical];

            if (document.getElementsByClassName("mc_mod").length !== arr_select_mod.length) {
                // 直接获取选中数据更新
                arr_no_select_msg = get_module_boundary(false, true);
            } else {
                arr_no_select_msg = false;
            }

            mc_show_hide_line_svg("block");
            // 回调更新连线 模块整体信息
            // box_return_new_value($("#mod_box_next"), { chg_type: "draw", arr_data: arr_select_mod,module_msg: arr_module_msg ,noselect_boundary: arr_no_select_msg});
            box_return_new_value($("#mod_box_next"), { chg_type: "draw", arr_data: arr_select_mod, module_msg: arr_module_msg, noselect_boundary: arr_no_select_msg });
            //  更新整体模块显示信息
            mc_compare_update_module_msg_txt(arr_no_select_msg, arr_module_msg);
            // 记录操作
            mc_layout_operate("move", obj_keyboard_operate_move_param);
            obj_keyboard_operate_move_param = null;
        }
        clearTimeout(mc_keyboard_operate_move_timer);
    }, 200);

    // 菜单栏跟随移动
    if ("function" === typeof menu_move && obj_down_mod) {
        var u_mod_box_scale = ui_mod_box_scale / 100;

        obj_down_mod = $(obj_down_mod)[0];
        menu_move((obj_down_mod.offsetLeft + obj_down_mod.offsetWidth / 2) * u_mod_box_scale, (obj_down_mod.offsetTop + obj_down_mod.offsetHeight / 2) * u_mod_box_scale);
    }
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    隐藏显示连线SVG盒子
 * 参数:
 *     @param { Promise<String> } str_display block/none
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.24
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_show_hide_line_svg(str_display) {
    if ("string" !== typeof str_display || 0 === str_display.length) {
        return false;
    }
    var obj_line_svg = document.getElementById("mc_hl_svg_layer_line");

    if (!obj_line_svg) {
        return false;
    }
    obj_line_svg.style.display = str_display;
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    框选元素键盘操作下的滚动条控制
 * 参数:
 *     @param { Promise<Object> } params 移动参数对象
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.03.03
 *      内容 : 所有代码
 ************************************************************************************************/
function select_mod_keydown_slider(params) {
    var o_mod_box = params.o_mod_box;
    var scroll_l = params.ui_scroll_l;
    var scroll_t = params.ui_scroll_t;

    // 当前画布缩放倍数
    var u_mod_box_scale = ui_mod_box_scale / 100;
    var i_grid_width = Math.ceil(params.i_grid_width * u_mod_box_scale);
    var ui_box_w = o_mod_box.width() / u_mod_box_scale;
    var ui_box_h = o_mod_box.height() / u_mod_box_scale;
    var s_l = scroll_l / u_mod_box_scale;
    var s_t = scroll_t / u_mod_box_scale;
    // 显示宽度
    var ui_modbox_w = ui_box_w - params.ui_max_right_w + s_l;
    var ui_modbox_h = ui_box_h - params.ui_scrollbar_width - params.ui_max_bot_h + s_t;

    // 滑动最大距离
    var ui_slider = params.ui_canvas_w - ui_box_w;
    var ui_slider_y = params.ui_canvas_h - ui_box_h;

    // 到达边界判定
    var ui_max_btn_t = mc_get_optsize_msg(params.o_max_bot_item)[1];
    var ui_max_right_l = mc_get_optsize_msg(params.o_max_right_item)[0];
    // var ui_arrive_tborder = params.ui_max_top_t - scroll_t;
    // var ui_arrive_lborder = params.ui_max_left_l - scroll_l;
    var ui_arrive_tborder = params.ui_max_top_t * u_mod_box_scale - scroll_t;
    var ui_arrive_lborder = params.ui_max_left_l * u_mod_box_scale - scroll_l;

    switch (params.ui_keycode) {
    case 38:
        if (ui_modbox_h > ui_max_btn_t && 0 !== s_l && 3 > ui_arrive_tborder) {
            o_mod_box.parent().scrollTop(scroll_t - i_grid_width);
        }
        break;
    case 40:
        if (ui_modbox_h <= ui_max_btn_t && ui_slider_y > s_t) {
            o_mod_box.parent().scrollTop(scroll_t + i_grid_width);
        }
        break;
    case 37:
        if (ui_modbox_w > ui_max_right_l && 0 !== s_l && 3 > ui_arrive_lborder) {
            o_mod_box.parent().scrollLeft(scroll_l - i_grid_width);
        }
        break;
    case 39:
        if (ui_modbox_w <= ui_max_right_l && ui_slider > s_l) {
            o_mod_box.parent().scrollLeft(scroll_l + i_grid_width);
        }
        break;
    default:
    }
}


/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    监听鼠标滚轮事件-覆盖按下ctrl+鼠标滑动页面放大缩小，操作箱体放大缩小
 * 参数:
 *     NA
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.5.14
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_scope_zoom() {
    // 覆盖鼠标滑动
    document.body.addEventListener("wheel", function (e) {
        if (e.ctrlKey) {
            if (0 > e.deltaY) {
                mc_mod_sizeup(e);
                // 操作滚动条
                // mc_mouse_center_scroll(e,true);
                e.preventDefault();
                return false;
            }
            if (0 < e.deltaY) {
                mc_mod_sizedown(e);
                // mc_mouse_center_scroll(e,false);
                e.preventDefault();
                return false;
            }
        }
        return true;
    }, { passive: false });
}

// 调用页面函数删除模组
function mc_delete_mod() {
    // eslint-disable-next-line no-undef
    mc_lang_delete_module();
}

/****************************选中相关*************************************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    只选中当前指定模块
 * 参数:
 *      @param { Promise<Object> } arr_mod 需要选中模块对象数组
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.13
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_mod_check(arr_mod) {
    if ("[object Array]" !== Object.prototype.toString.call(arr_mod)) {
        return false;
    }
    if (0 !== arr_select_mod.length) {
        mc_mod_uncheck(arr_select_mod);
    }

    for (var idx = 0; idx < arr_mod.length; idx++) {
        var obj_item = arr_mod[idx];

        mc_switch_mod_bg(obj_item[0], true);
        obj_item.addClass("selected");
    }
    arr_select_mod = arr_mod;
    mc_select_item_add_zindex(arr_mod);
    return arr_select_mod;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    选中模组取消选中
 * 参数:
 *    @param { Promise<Array> } arr_mod 选中模组数组 数组项存放为jq方式
 *    @param { Promise<Boolean> } b_return 是否返回当前arr_select_mod 可为��� 默认不返回
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      arr_mod
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_mod_uncheck(arr_mod, b_return) {
    if (0 === arr_mod.length) {
        return false;
    }
    for (var idx = 0; idx < arr_mod.length; idx++) {
        var obj_item = arr_mod[idx];

        mc_switch_mod_bg(obj_item[0], false);
        obj_item.removeClass("selected");
    }

    arr_select_mod = [];
    obj_down_mod = null;
    mc_clear_zindex();

    if (b_return) {
        box_return_new_value($(document.getElementById("mod_box_next")), arr_select_mod);
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    选中行列相同的模块
 * 参数:
 *    @param { Promise<String> } str_type 选中类型X=列 Y=行
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.18
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_select_ranks(str_type) {
    if ("string" !== typeof str_type || 0 === str_type.length) {
        return false;
    }
    var b_x = false;
    var b_y = false;
    // 符合偏移
    var arr_offset = [];
    var arr_select_mod_copy = [];
    var obj_ranks = null;

    if ("X" === str_type) {
        b_x = true;
        obj_ranks = mc_get_ranks_data(str_type);
    }
    if ("Y" === str_type) {
        b_y = true;
        obj_ranks = mc_get_ranks_data(str_type);
    }
    arr_select_mod_copy = $.extend(true, [], arr_select_mod);
    // 获取符合偏移数组 [X1,X2,,] / [Y1,Y2,,]
    for (var i = 0; i < arr_select_mod.length; i++) {
        var ary_offset = mc_get_optsize_msg(arr_select_mod[i][0]);

        if (b_x) {
            arr_offset.push(ary_offset[0]);
        }
        if (b_y) {
            arr_offset.push(ary_offset[1]);
        }
    }
    // 去重
    arr_offset = mc_unique(arr_offset);
    arr_select_mod = [];
    // 选中同行模块
    for (var j = 0; j < arr_offset.length; j++) {
        var arr_ranks = obj_ranks[arr_offset[j]];

        if (arr_ranks) {
            for (var index = 0; index < arr_ranks.length; index++) {
                var obj_item = arr_ranks[index];

                mc_switch_mod_bg(obj_item, true);
                obj_item.classList.add("selected");
                arr_select_mod.push($(obj_item));
            }
        }
    }
    if (0 === arr_select_mod.length) {
        arr_select_mod = arr_select_mod_copy;
    } else {
        mc_select_item_add_zindex(arr_select_mod);
        box_return_new_value($(document.getElementById("mod_box_next")), arr_select_mod);
    }
    // console.log("[行选]",arr_select_mod);
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    选中指定层叠数模块 - 选中上一个下一个/全选
 * 参数:
 *    @param { Promise<Array> } arr_list 当前层叠队列js对象数组
 *    @param { Promise<Number> } ui_stack 指定层 起始为1
 *    @param { Promise<Boolean> } b_all_select 是否全选
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.3
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_select_specify_stack(arr_list, ui_stack, b_all_select) {
    if ("[object Array]" !== Object.prototype.toString.call(arr_list)) {
        return false;
    }
    // mc_clear_zindex();
    mc_mod_uncheck(arr_select_mod);
    var o_target = null;

    if (b_all_select) {
        // 全选
        for (var i = 0; i < arr_list.length; i++) {
            o_target = arr_list[i];
            mc_select_module(o_target);
        }
    } else {
        if ("[object Number]" !== Object.prototype.toString.call(ui_stack)) {
            return false;
        }
        // 选中指定层
        o_target = arr_list[ui_stack - 1];
        mc_select_module(o_target);
        // arr_list.splice(ui_stack - 1,1);
        // arr_list.push(o_target);
    }
    mc_select_item_add_zindex(arr_select_mod);
    box_return_new_value($(document.getElementById("mod_box_next")), arr_select_mod);


    // return arr_list;
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    选中模块
 * 参数:
 *    @param { Promise<Object> } o_js
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.16
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_select_module(o_js) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(o_js)) {
        return false;
    }
    o_js.classList.add("selected");
    arr_select_mod.push($(o_js));
    mc_switch_mod_bg(o_js, true);
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取同行/列数据对象
 * 参数:
 *    @param { Promise<String> } str_type 选中类型X=列 Y=行
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      obj_offset = {
 *          X1: [OBJ1, OBJ2], // KEY为OFFSETLEFT VALUE为对应模块对象数组
 *          X2: [OBJ1,OBJ2],
 *      }
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.11.18
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_ranks_data(str_type) {
    if ("string" !== typeof str_type || 0 === str_type.length) {
        return false;
    }
    var module_list = document.getElementsByClassName("mc_mod");
    var obj_offset = {};
    var ui_index = 0;

    if ("X" === str_type) {
        ui_index = 0;
    }
    if ("Y" === str_type) {
        ui_index = 1;
    }

    for (var i = 0; i < module_list.length; i++) {
        var obj_target = module_list[i];
        var ui_x = mc_get_optsize_msg(obj_target)[ui_index];

        if (obj_offset[ui_x]) {
            obj_offset[ui_x].push(obj_target);
        } else {
            obj_offset[ui_x] = [obj_target];
        }
    }
    return obj_offset;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取鼠标所在位置模块及最大层叠数
 * 参数:
 *    @param { Promise<Object> } obj_menu_pot 菜单打开鼠标位置 {x:clientX, y:clientY}
 * 返回：
 *    @return { Promise<Array> }
 *      false 参数有误
 *      [符合条件js数组对象(按照层叠性小-大放置):Array, 最大层叠数:Nunber]
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.3
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_mouse_pot_module(obj_menu_pot) {
    if ("object" !== typeof obj_menu_pot) {
        return false;
    }
    // 获取鼠标点击位置-------转换过
    var obj_scroll = $(".mc_mod_box").parent();
    var obj_parent_offset = obj_scroll.offset();
    var ui_box_scale = ui_mod_box_scale / 100;
    var ui_menu_l = (obj_menu_pot.x - obj_parent_offset.left + obj_scroll.scrollLeft()) / ui_box_scale;
    var ui_menu_t = (obj_menu_pot.y - obj_parent_offset.top + obj_scroll.scrollTop()) / ui_box_scale;

    // 获取在鼠标范围元素------
    var module_list = document.getElementsByClassName("mc_mod");
    var arr_mose_range_module = [];

    for (var i = 0; i < module_list.length; i++) {
        var o_target = module_list[i];
        var ui_zindex = Number(o_target.style.zIndex);
        var arr_size = mc_get_optsize_msg(o_target, true);
        var arr_pot = mc_get_optsize_msg(o_target);
        var ui_item_l = arr_pot[0];
        var ui_item_t = arr_pot[1];
        var ui_item_maxl = ui_item_l + arr_size[0];
        var ui_item_maxt = ui_item_t + arr_size[1];

        if (ui_menu_l >= ui_item_l && ui_menu_l <= ui_item_maxl && ui_menu_t >= ui_item_t && ui_menu_t <= ui_item_maxt) {
            // 按照层叠性小-大放置
            if (isNaN(ui_zindex)) {
                // auto
                arr_mose_range_module.unshift(o_target);
            } else {
                if (arr_mose_range_module[ui_zindex]) {
                    arr_mose_range_module.splice(ui_zindex + 1, 0, o_target);
                } else {
                    arr_mose_range_module[ui_zindex] = o_target;
                }
            }
        }
    }

    // 去除空项
    arr_mose_range_module = mc_filter_tool(function (item) {
        return "[object Undefined]" !== Object.prototype.toString.call(item);
    },arr_mose_range_module);
    return [arr_mose_range_module, arr_mose_range_module.length];
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置选中模块宽高 箱体连接下不支持 格子数
 * 参数:
 *    @param { Promise<Number> } ui_chg_w 宽格子数 可为空
 *    @param { Promise<Number> } ui_chg_h 高格子数 可为空
 * 返回：
 *    @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_change_mod_size(ui_chg_w, ui_chg_h) {
    if ("[object Number]" !== Object.prototype.toString.call(ui_chg_w) && "[object Number]" !== Object.prototype.toString.call(ui_chg_h)) {
        return false;
    }
    if (b_create_grid) {
        return false;
    }
    var ui_grid = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));
    var b_chg_w = false;
    var b_chg_h = false;

    if ("number" === typeof ui_chg_w && !isNaN(ui_chg_w)) {
        b_chg_w = true;
    }
    if ("number" === typeof ui_chg_h && !isNaN(ui_chg_h)) {
        b_chg_h = true;
    }

    for (var i = 0; i < arr_select_mod.length; i++) {
        var obj_js = arr_select_mod[i][0];
        var obj_msg = mc_get_child_pot_size(obj_js);
        var ui_px = 0;
        var obj_size = obj_msg.o_size;
        var arr_size = obj_msg.str_size.split("X");
        var str_msg = "";

        if (b_chg_w) {
            str_msg = ui_chg_w + "X" + arr_size[1];
            ui_px = ui_chg_w * ui_grid;
            obj_js.style.width = ui_px + "px";
        }
        if (b_chg_h) {
            str_msg = arr_size[0] + "X" + ui_chg_h;
            ui_px = ui_chg_h * ui_grid;
            obj_js.style.height = ui_px + "px";
        }
        obj_size.innerText = str_msg;
        mc_update_module_msg(obj_js.id, false, str_msg);
    }
    return true;
}


/****************************数据处理/模块信息*****************************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    存储模块信息
 * 参数:
 *     @param { Promise<Object> } obj_jq 模块对象jq
 *     @param { Promise<String> } select_tip 选中bgimge字串 可为空
 *     @param { Promise<String> } no_select 未选中bgimge字串 可为空
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_save_module_msg(obj_jq, select_tip, no_select) {
    if ("[object Object]" !== Object.prototype.toString.call(obj_jq)) {
        return false;
    }
    var str_id = obj_jq.attr("id");
    var o_pot = mc_get_appoint_obj(obj_jq, "mod_pot");
    var o_size = mc_get_appoint_obj(obj_jq, "mod_size");
    var obj_msg = obj_module_msg[str_id];

    if (obj_msg) {
        obj_msg.o_pot = o_pot;
        obj_msg.o_size = o_size;
        if (!obj_msg.str_pot) {
            obj_msg.str_pot = o_pot.innerText;
        }
        if (!obj_msg.str_size) {
            obj_msg.str_size = o_size.innerText;
        }
    } else {
        obj_module_msg[str_id] = {
            "o_pot": o_pot,
            "o_size": o_size,
            "str_pot": o_pot.innerText,
            "str_size": o_size.innerText
        };
    }

    if (select_tip) {
        obj_module_msg[str_id].select_tip = select_tip;
    }
    if (no_select) {
        obj_module_msg[str_id].no_select = no_select;
    }
    return obj_module_msg[str_id];
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    存储模块信息 无真实dom时 存储偏移大小信息
 * 参数:
 *     @param { Promise<String> } str_id id
 *     @param { Promise<String> } str_size widthXheight
 *     @param { Promise<String> } str_pot left,top
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_save_undom_module_msg(str_id, str_size, str_pot) {
    if ("[object String]" !== Object.prototype.toString.call(str_id)) {
        return false;
    }
    if ("[object String]" !== Object.prototype.toString.call(str_size)) {
        return false;
    }
    if ("[object String]" !== Object.prototype.toString.call(str_pot)) {
        return false;
    }
    if (obj_module_msg[str_id]) {
        obj_module_msg[str_id].str_size = str_size;
        obj_module_msg[str_id].str_pot = str_pot;
    } else {
        obj_module_msg[str_id] = {
            str_size: str_size,
            str_pot: str_pot
        };
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    存储模组canvasbg字串（background-image）
 * 参数:
 *     @param { Promise<String> } str_id 模块id
 *     @param { Promise<String> } select_tip 选中bgimge字串
 *     @param { Promise<String> } no_select 未选中bgimge字串
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.01.22
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_save_mod_canvasbg(str_id, select_tip, no_select) {
    if ("string" !== typeof str_id || 0 === str_id.length) {
        return false;
    }
    if ("string" !== typeof select_tip || 0 === select_tip.length) {
        return false;
    }
    if ("string" !== typeof no_select || 0 === no_select.length) {
        return false;
    }
    if (obj_module_msg[str_id]) {
        obj_module_msg[str_id].select_tip = select_tip;
        obj_module_msg[str_id].no_select = no_select;
    } else {
        obj_module_msg[str_id] = {};
        obj_module_msg[str_id].select_tip = select_tip;
        obj_module_msg[str_id].no_select = no_select;
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取模块canvasbg
 * 参数:
 *     @param { Promise<String> } str_id 模块id
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误/无此数据
 *      {select_tip: 选中,no_select: 未选中}
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.01.22
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_canvasbg_msg(str_id) {
    if ("string" !== typeof str_id || 0 === str_id.length) {
        return false;
    }
    var obj_msg = obj_module_msg[str_id];

    if (obj_msg) {
        var select_tip = obj_msg.select_tip;
        var no_select = obj_msg.no_select;

        if (select_tip && no_select) {
            return { select_tip: select_tip, no_select: no_select };
        }
    }
    return false;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    更改模组canvasbg操作
 * 参数:
 *     @param { Promise<Object> } obj_js js元素
 *     @param { Promise<Object> } b_select 是否切换选中
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 更改成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.01.22
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_switch_mod_bg(obj_js, b_select) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_js)) {
        return false;
    }
    var obj_bg = mc_get_canvasbg_msg(obj_js.id);

    if (obj_bg && b_create_grid) {
        if (b_select) {
            obj_js.style.backgroundImage = "url(" + obj_bg.select_tip + ")";
        } else {
            obj_js.style.backgroundImage = "url(" + obj_bg.no_select + ")";
        }
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    删除模块信息
 * 参数:
 *     @param { Promise<String> } str_id 删除模块id
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_delete_module_msg(str_id) {
    if ("[object String]" !== Object.prototype.toString.call(str_id)) {
        return false;
    }
    obj_module_msg[str_id] = null;
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    清空模块信息
 * 参数:
 *     无
 * 返回：
 *     NA
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_clear_module_msg() {
    obj_module_msg = {};
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    更新模块信息
 * 参数:
 *     @param { Promise<String> } str_id 模块id
 *     @param { Promise<String> } str_update_pot 位置信息字串 L,T 可为空
 *     @param { Promise<String> } str_update_size 大小信息子窗 W,H 可为空
 *     @param { Promise<String> } select_tip 选中canvasbg字串 可为空
 *     @param { Promise<String> } no_select 未选中canvasbg字串 可为空
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_update_module_msg(str_id, str_update_pot, str_update_size, select_tip, no_select) {
    if ("[object String]" !== Object.prototype.toString.call(str_id)) {
        return false;
    }
    var obj_msg = obj_module_msg[str_id];

    if (obj_msg) {
        if (str_update_pot && -1 !== str_update_pot.indexOf(",")) {
            obj_msg.str_pot = str_update_pot;
        }
        if (str_update_size && -1 !== str_update_size.indexOf("X")) {
            obj_msg.str_size = str_update_size;
        }
        if ("string" === typeof select_tip && 0 !== select_tip.length) {
            obj_msg.select_tip = select_tip;
        }
        if ("string" === typeof no_select && 0 !== no_select.length) {
            obj_msg.no_select = no_select;
        }
    }
    return true;
}


/****************************其他*****************************************************************/
/*************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置信息框定位
 * 参数:
 *    无
 * 返回：
 *     @return { Promise<Boolean> }
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.5.24
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_set_canvas_msg_style() {
    // var obj_msg = document.getElementById("mc_canvas_msg");
    var obj_msg = document.getElementsByClassName("mc_msg_menu_box")[0];

    if (obj_msg && !b_istouch) {
        obj_msg.style.bottom = "2px";
        obj_msg.style.right = "2px";
    }
    return true;
}


/*************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    操作返回新值/框选对象
 * 参数:
 *    @param { Promise<Object> } o_obj 触发函数的对象
 *    @param { Promise<String> } new_value 新值/框选对象
 *    @param { Promise<Boolean> } b_operate_mod_end 操作结束回调
 * 返回：
 *    无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.03.05
 *      内容 : 所有代码
 ************************************************************************************************/
function box_return_new_value(o_obj, new_value, b_operate_mod_end) {
    var str_fun_name = o_obj.attr(g_str_attr_lab_val_chg);

    if (b_operate_mod_end) {
        str_fun_name = o_obj.attr(g_str_attr_operate_mod_end);
    }

    if ("string" === typeof str_fun_name && 0 < str_fun_name.length) {
        var fun_callback = g_obj_func_name_map[str_fun_name];

        if ("function" === typeof fun_callback) {
            fun_callback(new_value);
        }
    }
}

/*************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    取出函数名
 * 参数:
 *    @param {Function} func 函数
 * 返回：
 *    @return { Promise<String> }
 *     函数名称
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2019.11.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_func_key(func) {
    if ("function" !== typeof func) {
        return "";
    }

    /* 如果有必要，考虑使用 MDK 算func的哈希作为key */
    var func_name = func.toString().split("(")[0].split(" ")[1];

    func_name = func_name.trim();
    func_name = func_name.toLowerCase();

    if ("string" === typeof func_name && 0 < func_name.length && "function" !== typeof g_obj_func_name_map[func_name]) {
        g_obj_func_name_map[func_name] = func;
    }

    return func_name;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取模块对象内的指定dom对象
 * 参数:
 *     @param { Promise<Object> } obj_jq 模块jq对象
 *     @param { Promise<String> } str_class_name 类名
 *     @param { Promise<Boolean> } b_return_jq 是否返回jq对象 可为空 默认返回js对象
 * 返回：
 *     @return { Promise<Object> }
 *     指定js对象
 *     false 参数错误/没有这个类名
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.30
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_appoint_obj(obj_jq, str_class_name, b_return_jq) {
    if ("[object HTMLDivElement]" === Object.prototype.toString.call(obj_jq)) {
        obj_jq = $(obj_jq);
    }
    if ("[object Object]" !== Object.prototype.toString.call(obj_jq)) {
        return false;
    }
    if ("[object String]" !== Object.prototype.toString.call(str_class_name)) {
        return false;
    }
    var o_jq = null;

    if ("mod_show_name" === str_class_name || "chip_name" === str_class_name || "mod_size" === str_class_name || "mod_pot" === str_class_name || "mod_list_idx" === str_class_name) {
        o_jq = obj_jq.children(".mod_msg_box").children("." + str_class_name);
        return b_return_jq ? o_jq : o_jq[0];
    }
    if ("mod_hub_div" === str_class_name) {
        o_jq = obj_jq.children(".mod_hub_box").children("." + str_class_name);
        return b_return_jq ? o_jq : o_jq[0];
    }
    if ("card_idx" === str_class_name) {
        o_jq = obj_jq.children(".mc_mod_right_bto").children("." + str_class_name);
        return b_return_jq ? o_jq : o_jq[0];
    }
    if ("mc_lock_icon" === str_class_name) {
        o_jq = obj_jq.children(".mc_mod_right_top").children("." + str_class_name);
        return b_return_jq ? o_jq : o_jq[0];
    }
    return false;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取指定元素滚动条宽度
 * 参数:
 *     @param { Promise<String> } str_id 指定元素id
 * 返回：
 *     @return { Promise<Number> }
 *     ui_scrollbar_width 滚动条宽度
 *     0 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.5.18
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_scrollbar_width(str_id) {
    if ("string" !== typeof str_id || 0 === str_id.length) {
        return 0;
    }
    var obj_p = document.createElement("p");
    var ui_scrollbar_width = 0;

    obj_p.style.width = "100px";
    obj_p.style.height = "100px";
    obj_p.style.overflow = "scroll";
    document.getElementById(str_id).appendChild(obj_p);
    ui_scrollbar_width = obj_p.offsetWidth - obj_p.clientWidth;
    obj_p.remove();

    return ui_scrollbar_width;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    清空选中模组数组
 * 参数:
 *     无
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.5.28
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_empty_arr_select_mod() {
    arr_select_mod = [];
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    指定元素获得焦点 参数为空则为canvasbg点击事件-使mc_mod_box获取焦点
 * 参数:
 *     @param { Promise<String> } str_id 指定元素id jq方式传入 可为空
 *     @param { Promise<Object> } o_parent 带有滚动条的父级 jq方式 可为空
 * 返回：
 *    @return { Promise<Boolean> }
 *     true 设置成功
 *     false 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.08
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_focus(str_id, o_parent) {
    var o_box = $(".mc_mod_box").parent();
    var str_class = ".mc_mod_box";

    if (str_id && "string" === typeof str_id && o_parent && "object" === typeof o_parent) {
        o_box = o_parent;
        str_class = str_id;
    }
    var scroll_t = o_box.scrollTop();
    var scroll_l = o_box.scrollLeft();

    $(str_class).focus();
    if ((0 !== scroll_t || 0 !== scroll_l) && 0 !== o_box.length) {
        o_box.scrollLeft(scroll_l).scrollTop(scroll_t);
    }
    return true;
}

// 提示信息调用函数
function alert_get_focus() {
    mc_get_focus();
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    设置普通元素(非链接元素及表单元素)是否获得焦点
 * 参数:
 *     @param { Promise<String> } str_id 指定元素id jq方式传入
 *     @param { Promise<Boolean> } b_focus 是否获得焦点 true获得
 * 返回：
 *     @return { Promise<Boolean> }
 *     true 设置成功
 *     false 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.06
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_allow_get_focus(str_id, b_focus) {
    if ("string" !== typeof str_id || 0 === str_id.length || "boolean" !== typeof b_focus) {
        return false;
    }
    if (b_focus) {
        $(str_id).attr("tabindex", -1);
    } else {
        $(str_id).removeAttr("tabindex");
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取边界元素及边界距离
 * 参数:
 *     @param { Promise<Array> } arr_select 选中模组数组
 *     @param { Promise<Object> } params 实列对象 可为空
 *     @param { Promise<b_filter_lock> } b_filter_lock true 不过滤锁定元素 可为空
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 无选中模组
 *      obj_boundary
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.5.27
 *      内容 : 所有代码
 ************************************************************************************************/
function get_boundary_obj(arr_select, params, b_filter_lock) {
    if (0 === arr_select.length) {
        return false;
    }
    var obj_boundary = {
        // 点击元素与边界元素距离
        ui_boundary_left: Math.pow(2, 32),
        ui_boundary_top: Math.pow(2, 32),
        ui_boundary_right: 0,
        ui_boundary_bot: 0,
        // 框选边界元素
        o_max_left_item: "",
        o_max_top_item: "",
        o_max_right_item: "",
        o_max_bot_item: "",
        // 边界元素偏移/宽度计算
        ui_max_left_l: 0,
        ui_max_top_t: 0,
        ui_max_right_w: 0,
        ui_max_bot_h: 0
    };

    if (params) {
        obj_boundary = params;
    }

    for (var idx = 0; idx < arr_select.length; idx++) {
        var select_mod = $(arr_select[idx])[0];
        var arr_size = mc_get_optsize_msg(select_mod, true);
        var arr_pot = mc_get_optsize_msg(select_mod);
        var ui_mod_h = arr_size[1];
        var ui_mod_left = arr_pot[0];
        var ui_mod_top = arr_pot[1] + ui_mod_h;

        if (!b_filter_lock) {
            // 过滤锁定元素
            if ($(arr_select[idx]).hasClass("mc_lock")) {
                arr_select.splice(idx, 1);
                idx--;
                continue;
            }
        }

        if (obj_boundary.ui_boundary_left > ui_mod_left) {
            obj_boundary.ui_boundary_left = ui_mod_left;
            obj_boundary.o_max_left_item = select_mod;
        }
        if (obj_boundary.ui_boundary_top > ui_mod_top) {
            obj_boundary.ui_boundary_top = ui_mod_top;
            obj_boundary.o_max_top_item = select_mod;
        }

        if (obj_boundary.ui_boundary_right <= ui_mod_left) {
            obj_boundary.ui_boundary_right = ui_mod_left;
            obj_boundary.o_max_right_item = select_mod;
        }
        if (obj_boundary.ui_boundary_bot <= Math.abs(ui_mod_top)) {
            obj_boundary.ui_boundary_bot = ui_mod_top;
            obj_boundary.o_max_bot_item = select_mod;
        }
    }
    if (1 === arr_select.length && "" === obj_boundary.o_max_right_item) {
        obj_boundary.o_max_right_item = arr_select[0][0];
        obj_boundary.o_max_bot_item = arr_select[0][0];
    }
    obj_boundary.ui_max_left_l = mc_get_optsize_msg(obj_boundary.o_max_left_item)[0];
    obj_boundary.ui_max_top_t = mc_get_optsize_msg(obj_boundary.o_max_top_item)[1];
    obj_boundary.ui_max_right_w = mc_get_optsize_msg(obj_boundary.o_max_right_item, true)[0];
    obj_boundary.ui_max_bot_h = mc_get_optsize_msg(obj_boundary.o_max_bot_item, true)[1];
    return obj_boundary;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    根据由上至下从左到右 整理选中模组数组
 * 参数:
 *     @param { Promise<Boolean> } b_select 是否为全选 false全选
 *     @param { Promise<Boolean> } b_arrow 只进行排列 可为空
 *     @param { Promise<Boolean> } b_selected true只对选中项进行排列 可为空
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      arr_mod
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.10.10
 *      内容 : 所有代码
 ************************************************************************************************/
function set_arr_select_mod(b_select, b_arrow,b_selected) {
    if ("[object Boolean]" !== Object.prototype.toString.call(b_select)) {
        return false;
    }

    var obj_list_pot = document.getElementsByClassName("mod_pot");
    // 获取位置信息对象/若存在检索对象直接存入位置信息
    var arr_pnt = [];

    if (b_select) {
        var arr_mod = document.getElementsByClassName("selected");

        if (arr_mod.length === obj_list_pot.length) {
            arr_pnt = obj_list_pot;
        } else {
            for (var index_pnt = 0; index_pnt < arr_mod.length; index_pnt++) {
                var obj_msg = mc_get_child_pot_size(arr_mod[index_pnt]);

                if (obj_msg && obj_msg.o_pot) {
                    arr_pnt.push(obj_msg.o_pot);
                }
            }
        }
    } else {
        arr_pnt = obj_list_pot;
    }

    if (0 === arr_pnt.length) {
        return arr_pnt;
    }
    var arr_row = [];
    var arr_result = [];

    for (var idx = 0; idx < arr_pnt.length; idx++) {
        var obj_pot = arr_pnt[idx];
        var arr_pot = obj_pot.innerText.split(",");

        if (b_selected && !$(obj_pot.parentNode.parentNode).hasClass("selected")) {
            continue;
        }

        if (arr_row[Number(arr_pot[1])]) {
            if (arr_row[Number(arr_pot[1])][Number(arr_pot[0])]) {
                arr_row[Number(arr_pot[1])].splice(Number(arr_pot[0]), 0, obj_pot);
            } else {
                arr_row[Number(arr_pot[1])][Number(arr_pot[0])] = obj_pot;
            }
        } else {
            arr_row[Number(arr_pot[1])] = [];
            arr_row[Number(arr_pot[1])][Number(arr_pot[0])] = obj_pot;
        }
    }
    arr_row = mc_filter_tool(function (item) {
        return "[object Undefined]" !== Object.prototype.toString.call(item);
    },arr_row);


    for (var index = 0; index < arr_row.length; index++) {
        var arr_target = arr_row[index];

        arr_target = mc_filter_tool(function (item) {
            return "[object Undefined]" !== Object.prototype.toString.call(item);
        },arr_target);
        for (var arr_idx = 0; arr_idx < arr_target.length; arr_idx++) {
            var obj_pnt = arr_target[arr_idx].parentNode.parentNode;

            arr_result.push($(obj_pnt));
        }
    }

    if (!b_arrow && 0 !== arr_result.length) {
        // 保存排列起始位置
        ui_left = arr_result[0].position().left;
        ui_top = arr_result[0].position().top;
    }
    return arr_result;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    选中模组及hub_line添加z-index属性
 * 参数:
 *     @param { Promise<Array> } arr_obj 选中模组数组
 * 返回：
 *     @return { Promise<Boolean> }
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.10
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_select_item_add_zindex(arr_obj) {
    if (!arr_obj) {
        return false;
    }
    var arr_obj_line = $(".mod_hub_Line");
    var b_line = false;

    // 无论是否改变层叠 显示线
    if (0 !== arr_obj_line.length) {
        $(".mod_hub_Line").css("display", "block");
        b_line = true;
    }

    if (0 === arr_obj.length || arr_obj.length === $(".mc_mod").length) {
        return false;
    }
    // 存储模组id数组
    var arr_mod_id = [];

    for (var idx = 0; idx < arr_obj.length; idx++) {
        var obj_mod = arr_obj[idx];
        var ui_zindex = Number(obj_mod.attr("addzindex"));

        arr_mod_id.push(obj_mod.attr("id"));
        if (isNaN(ui_zindex)) {
            ui_zindex = 0;
        }
        // add_zindex 标识添加层叠性的元素
        obj_mod.css("z-index", 21473 + ui_zindex).addClass("add_zindex");
    }
    if (b_line && 0 !== arr_mod_id.length) {
        for (var idx_line = 0; idx_line < arr_obj_line.length; idx_line++) {
            var obj_line = arr_obj_line.eq(idx_line);
            var arr_id = obj_line.attr("id").split("_");

            for (var idx_mod_id = 0; idx_mod_id < arr_mod_id.length; idx_mod_id++) {
                var str_mod_id = arr_mod_id[idx_mod_id];

                // 判断选中模组上是否存在line
                if (str_mod_id === arr_id[0] || str_mod_id === arr_id[1]) {
                    // 设置line层叠性
                    obj_line.css("z-index", 31474).addClass("add_zindex");
                    break;
                }
            }
        }
    }

    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    清除模组及hub_line设置的z-index
 * 参数:
 *     无
 * 返回：
 *     无
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.6.10
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_clear_zindex() {
    var arr_obj = document.getElementsByClassName("add_zindex");
    var ui_len = arr_obj.length;

    for (var idx = 0; idx < ui_len; idx++) {
        var o_target = arr_obj[idx];
        var ui_index = o_target.getAttribute("addzindex");

        if (ui_index) {
            o_target.style.zIndex = Number(ui_index);
        } else {
            o_target.style.zIndex = "auto";
        }

        // if (-1 !== o_target.className.indexOf("mod_hub_Line")) {
        //     o_target.style.zIndex = ui_len;
        // }

        // line svg
        if ("string" === typeof (o_target.className)) {
            if (-1 !== o_target.className.indexOf("mod_hub_Line")) {
                o_target.style.zIndex = ui_len;
            }
        } else {
            if ("line" === o_target.tagName) {
                if (-1 !== o_target.className.animVal.indexOf("mod_hub_Line") || -1 !== o_target.className.baseVal.indexOf("mod_hub_Line")) {
                    o_target.style.zIndex = ui_len;
                }
            }
        }
    }
    $(arr_obj).removeClass("add_zindex");
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    更新模组显示位置
* 参数:
*    @param { Promise<Object> } obj js
*    @param { Promise<Number> } ui_x 格子数 可为空
*    @param { Promise<Number> } ui_y 格子数 可为空
*    @param { Promise<Boolean> } b_computer 是否需要计算于外接矩形的偏移 可为空默认不计算
*    @param { Promise<Object> } obj_operate 操作参数对象
* 返回：
*    @return { Promise<Boolean> }
*     false 参数有误
*     true 更新成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.9.3
*      内容 : 所有代码
************************************************************************************************/
function update_mod_pot(obj, ui_x, ui_y, b_computer, obj_operate) {
    if ("object" !== typeof obj) {
        return false;
    }
    var obj_msg = mc_get_child_pot_size(obj);
    var obj_pot = obj_msg.o_pot;
    var arr_pot = obj_msg.str_pot.split(",");
    var ui_update_x = Number(arr_pot[0]);
    var ui_update_y = Number(arr_pot[1]);

    if (obj_operate && obj_operate.undo) {
        obj_operate.undo.push([ui_update_x, ui_update_y]);
    }
    if (b_computer) {
        var str_text = judge_transform_mod_pot(obj, ui_x, ui_y, ui_update_x, ui_update_y);

        if (str_text) {
            obj_pot.innerText = str_text;
            mc_update_module_msg(obj.id, str_text, false);
            if (obj_operate && obj_operate.redo) {
                obj_operate.redo.push(str_text.split(","));
            }
            return true;
        }
    }
    if ("number" === typeof ui_x) {
        ui_update_x = ui_x;
    }
    if ("number" === typeof ui_y) {
        ui_update_y = ui_y;
    }

    if (obj_operate && obj_operate.redo) {
        obj_operate.redo.push([ui_update_x, ui_update_y]);
    }
    obj_pot.innerText = ui_update_x + "," + ui_update_y;
    mc_update_module_msg(obj.id, ui_update_x + "," + ui_update_y, false);
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    拖拽更新模组显示位置
* 参数:
*    @param { Promise<Object> } obj_modblks 数据对象
* 参数备注:
*   obj_modblks = {
*       obj: js对象
*       ui_x: x偏移格子数
*       ui_y: y偏移格子数
*       ui_lc: 与外接矩形x差格子数
*       ui_tc: 与外接矩形y差格子数
*   }
* 返回：
*    @return { Promise<Boolean> }
*     false 参数有误/无需更新
*     true 更新成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.11.30
*      内容 : 所有代码
************************************************************************************************/
function update_draw_mod_pot(obj_modblks) {
    if ("[object Object]" !== Object.prototype.toString.call(obj_modblks)) {
        return false;
    }
    var obj_js = obj_modblks.obj;
    var obj_msg = mc_get_child_pot_size(obj_js);
    var obj_pot = obj_msg.o_pot;
    var str_before_pot_txt = obj_msg.str_pot;
    var str_txt = obj_modblks.ui_x - obj_modblks.ui_lc + "," + (obj_modblks.ui_y - obj_modblks.ui_tc);

    if (str_before_pot_txt === str_txt) {
        return false;
    }
    obj_pot.innerText = str_txt;
    mc_update_module_msg(obj_js.id, str_txt, false);
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    更新模组大小
* 参数:
*    @param { Promise<Object> } obj js
*    @param { Promise<Number> } ui_w
*    @param { Promise<Number> } ui_h
* 返回：
*    @return { Promise<Boolean> }
*     false 参数有误
*     true 更新成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.10.15
*      内容 : 所有代码
************************************************************************************************/
function update_mod_size(obj, ui_w, ui_h) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj) || "[object Number]" !== Object.prototype.toString.call(ui_w) || "[object Number]" !== Object.prototype.toString.call(ui_h)) {
        return false;
    }
    var str_size = ui_w + "X" + ui_h;
    var obj_target = mc_get_appoint_obj($(obj), "mod_size");

    if (obj_target) {
        obj_target.innerText = str_size;
    }
    return true;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    获取模块位置、大小子元素、位置信息字串、大小信息字串
* 参数:
*    @param { Promise<Object> } obj_target js
*    @param { Promise<Boolean> } b_get_txt true 不获取信息字串 可为空默认获取
* 返回：
*    @return { Promise<Object> }
*     obj_child = {o_pot:object,o_size:object} / 若模块信息存在 {o_pot:object, o_size:object, str_pot:string, str_size:string}
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.12.10
*      内容 : 所有代码
************************************************************************************************/
function mc_get_child_pot_size(obj_target, b_get_txt) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target)) {
        return false;
    }
    var obj_msg = obj_module_msg[obj_target.id];

    if (obj_msg) {
        var ui_len = Object.keys(obj_msg).length;

        if (2 < ui_len) {
            return obj_msg;
        }
    }
    var obj_child = {
        o_pot: null,
        o_size: null,
        str_pot: "",
        str_size: ""
    };

    obj_target = $(obj_target);
    obj_child.o_pot = mc_get_appoint_obj(obj_target, "mod_pot");
    obj_child.o_size = mc_get_appoint_obj(obj_target, "mod_size");
    if (!b_get_txt) {
        obj_child.str_pot = obj_child.o_pot.innerText;
        obj_child.str_size = obj_child.o_size.innerText;
    }

    var str_grid = document.getElementById("mod_box_next").getAttribute("grid_w");
    var obj_canvasbg = mc_judge_create_canvasbg(obj_target.attr("mod_id"), str_grid);
    var select_tip = false;
    var no_select = false;

    if ("[object Object]" === Object.prototype.toString.call(obj_canvasbg)) {
        select_tip = obj_canvasbg.select_url;
        no_select = obj_canvasbg.img_url;
    }
    obj_child = mc_save_module_msg(obj_target, select_tip, no_select);
    return obj_child;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    数组去重
* 参数:
*    @param { Promise<Array> } arr_data
* 返回：
*    @return { Promise<Array> }
*     ary 去重数组
*     false 参数有误
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.11.18
*      内容 : 所有代码
************************************************************************************************/
function mc_unique(arr_data) {
    if (Array.isArray(arr_data)) {
        var ary = [];

        for (var i = 0; i < arr_data.length; i++) {
            if (-1 === ary.indexOf(arr_data[i])) {
                ary.push(arr_data[i]);
            }
        }
        return ary;
    }
    return false;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    替换/添加css规则 参数四替换
 * 参数:
 *    @param { Promise<String> } stylesheets_name 样式表名称 id
 *    @param { Promise<String> } rule_name 规则名称
 *    @param { Promise<String> } str_style_rule 样式规则
 *    @param { Promise<Boolean> } b_add true为替换 可为空
 * 返回：
 *    @returns { Promise<Object> } true || false
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.2
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_update_css_rules(stylesheets_name, rule_name, str_style_rule, b_add) {
    if ("string" !== typeof stylesheets_name || "string" !== typeof rule_name || "string" !== typeof str_style_rule) {
        return false;
    }

    if ("" === stylesheets_name.trim() || "" === rule_name.trim() || "" === str_style_rule.trim()) {
        return false;
    }

    var obj_styleSheets = document.styleSheets;

    for (var idx = 0; idx < obj_styleSheets.length; idx++) {
        var str_styles_id = obj_styleSheets[idx].ownerNode.id;

        if ("undefined" !== str_styles_id && stylesheets_name === str_styles_id) {
            var obj_cur_stylesheet = document.styleSheets[idx];
            var cssrules_list = null;

            // chome / firefox
            if (obj_cur_stylesheet.cssRules) {
                cssrules_list = obj_cur_stylesheet.cssRules;
            } else {
                // ie
                if (obj_cur_stylesheet.rules) {
                    cssrules_list = obj_cur_stylesheet.rules;
                }
            }
            var b_exist = false;

            for (var index = 0; index < cssrules_list.length; index++) {
                var item = cssrules_list[index];

                if (!item) {
                    continue;
                }

                // update rules
                if (item.selectorText === rule_name) {
                    b_exist = true;
                    if (!b_add) {
                        item.style.cssText = str_style_rule;
                    }
                    break;
                }
            }

            if (!b_exist) {
                obj_cur_stylesheet.addRule(rule_name, str_style_rule);
            }

            return true;
        }
    }

    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    更新显示信息参数
 * 参数:
 *    @param { Promise<Array> } arr_data 显示信息参数 [chip,pot,size,hub,idx,card_name,line]
 * 返回：
 *    @returns { Promise<Boolean> }
 *      false 参数错误
 *      true 更新成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_update_info_disp_data(arr_data) {
    if ("[object Array]" !== Object.prototype.toString.call(arr_data)) {
        return false;
    }
    arr_info_disp = arr_data;
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    转换信息显示样式字串
 * 参数:
 *    无
 * 返回：
 *    @returns { Promise<Array> }
 *      [display:type]
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.12.11
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_info_disp_style() {
    var arr_style = [];

    for (var i = 0; i < arr_info_disp.length; i++) {
        var str_display = arr_info_disp[i] ? "display:block;" : "display:none;";

        arr_style.push(str_display);
    }
    return arr_style;
}

/****************************变换相关*****************************************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    构造变换参数对象 --初始创建变换元素时
 * 参数:
 *     @param {Promise<String>} str_scale_x X缩放倍数
 *     @param {Promise<String>} str_scale_y Y缩放倍数
 *     @param {Promise<String>} str_rotate_angle 旋转角度
 *     @param {Promise<String>} str_morror_type 镜像类型
 * 返回：
 *     @returns {Promise<String>}
 *      null 不设置变换
 *      旋转缩放弹出菜单JSON字串
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.10.14
 *      内容 : 所有代码
 ************************************************************************************************/
function construct_transform_params_obj(str_scale_x, str_scale_y, str_rotate_angle, str_morror_type) {
    if ("[object String]" !== Object.prototype.toString.call(str_scale_x) || "[object String]" !== Object.prototype.toString.call(str_scale_y) || "[object String]" !== Object.prototype.toString.call(str_rotate_angle) || "[object String]" !== Object.prototype.toString.call(str_morror_type)) {
        return null;
    }
    var ui_scale_x = Number(str_scale_x);
    var ui_scale_y = Number(str_scale_y);
    var ui_rotate_angle = Number(str_rotate_angle);
    var ui_mirror_type = Number(str_morror_type);

    // 范围限制
    if (0.1 > ui_scale_x || 65535 < ui_scale_x) {
        str_scale_x = "1.0";
    }
    if (0.1 > ui_scale_y || 65535 < ui_scale_y) {
        str_scale_y = "1.0";
    }
    if (0 > ui_rotate_angle || 360 < ui_rotate_angle) {
        str_rotate_angle = "0";
    }
    if (0 > ui_mirror_type || 2 < ui_mirror_type) {
        str_morror_type = "0";
    }
    var obj_params = {
        MC_LANG_X_DIRECTION: { val: str_scale_x },
        MC_LANG_Y_DIRECTION: { val: str_scale_y },
        MC_LANG_ROTATION_ANGLE: { val: str_rotate_angle },
        MC_LANG_MIRROR_IMAGE: { val: str_morror_type }
    };

    return obj_params;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    变换应用 撤销重做时
 * 参数:
 *     @param {Promise<Array>} ary_mod 设置元素 jq元素数组
 *     @param {Promise<Object>} obj_data 设置参数对象 大屏连接中存在设置模块宽高字串
 *     @param {Promise<Boolean>} b_update_msg 是否更新整体模块信息; 默认更新；为false时不更新
 * 返回：
 *     @returns {Promise<Object>}
 *      null 参数有误
 *      {str_transform_msg:变换标识属性值字串, str_transform_val:模块transform属性值,str_transform_child_val:子元素transform属性值}
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.10.14
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_transform_operate_apply(ary_mod, obj_data, b_update_msg) {
    if ("[object Array]" !== Object.prototype.toString.call(ary_mod) || "[object Object]" !== Object.prototype.toString.call(obj_data)) {
        return {};
    }

    var ui_grid = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));
    // 缩放大小,旋转角度
    var ui_scale_x = Number(obj_data.MC_LANG_X_DIRECTION.val), ui_scale_y = Number(obj_data.MC_LANG_Y_DIRECTION.val);
    var ui_rotate_angle = Number(obj_data.MC_LANG_ROTATION_ANGLE.val);
    var ui_mirror_image = Number(obj_data.MC_LANG_MIRROR_IMAGE.val);
    var ui_cut_l = Number(obj_data.MC_LANG_HORZ_HEAD.val);
    var ui_cut_r = Number(obj_data.MC_LANG_HORZ_RAIL.val);
    var ui_cut_t = Number(obj_data.MC_LANG_VERTICAL_HEAD.val);
    var ui_cut_b = Number(obj_data.MC_LANG_VERTICAL_TAIL.val);
    var transform_val = "";
    var transform_child_val = "";
    // 镜像类型
    var str_mirror_type = "";
    var transform_msg = {
        angle: ui_rotate_angle,
        scale_x: ui_scale_x,
        scale_y: ui_scale_y,
        mirror: ui_mirror_image,
        cut_l: ui_cut_l,
        cut_r: ui_cut_r,
        cut_t: ui_cut_t,
        cut_b: ui_cut_b
    };
    var ui_cut_x = ui_cut_l + ui_cut_r;
    var ui_cut_y = ui_cut_t + ui_cut_b;

    for (var j = 0; j < ary_mod.length; j++) {
        var obj_transform_msg = JSON.parse(JSON.stringify(transform_msg));
        var obj_target = ary_mod[j][0];
        var obj_msg = mc_get_child_pot_size(obj_target);
        var arr_size = obj_msg.str_size.split("X");
        var u_w = Number(arr_size[0]) - ui_cut_x;
        var u_h = Number(arr_size[1]) - ui_cut_y;

        if (0 >= u_w) {
            u_w = Number(arr_size[0]);
            obj_transform_msg.cut_l = obj_transform_msg.cut_r = ui_cut_x = 0;
        }
        if (0 >= u_h) {
            u_h = Number(arr_size[1]);
            obj_transform_msg.cut_t = obj_transform_msg.cut_b = ui_cut_y = 0;
        }
        var ui_size_w = (Number(arr_size[0]) - ui_cut_x) * ui_scale_x;
        var ui_size_h = (Number(arr_size[1]) - ui_cut_y) * ui_scale_y;
        var str_update_size = ui_size_w + "X" + ui_size_h;

        obj_target.style.width = ui_size_w * ui_grid + "px";
        obj_target.style.height = ui_size_h * ui_grid + "px";
        obj_msg.o_size.innerText = str_update_size;
        obj_target.setAttribute("mod_wg", ui_size_w);
        obj_target.setAttribute("mod_hg", ui_size_h);
        mc_update_module_msg(obj_target.id, false, str_update_size);
        mc_addup_transform_cut(obj_target,obj_transform_msg);
        if (1 === ui_mirror_image) {
            // 水平翻转
            str_mirror_type = "rotateY(180deg)translateX(-" + obj_target.offsetWidth * ui_scale_x + "px) ";
            transform_child_val = "rotateY(180deg)";
        }
        if (2 === ui_mirror_image) {
            // 垂直翻转
            str_mirror_type = "rotateX(180deg)translateY(-" + obj_target.offsetHeight * ui_scale_y + "px) ";
            transform_child_val = "rotateX(180deg)";
        }
        transform_val = "rotateZ(" + ui_rotate_angle + "deg) " + str_mirror_type + "scale3d(1,1,1)";
        obj_target.setAttribute("split_x",0);
        obj_target.setAttribute("split_y",0);
        mc_get_rotate_crisis(obj_target, obj_transform_msg, obj_msg);
        css3_transform(obj_target, transform_val);

        // 显示信息正向
        var child_list = obj_target.childNodes;
        var child_msg_list = child_list[0].childNodes;

        for (var idx_child = 0; idx_child < child_msg_list.length; idx_child++) {
            var obj_child = child_msg_list[idx_child];

            css3_transform(obj_child, transform_child_val);
        }
        css3_transform(child_list[1].childNodes[0], transform_child_val);
        css3_transform(child_list[2].childNodes[0], transform_child_val);
        if (!b_create_grid) {
            // 卡下标
            css3_transform(child_list[3].childNodes[0], transform_child_val);
        }
    }


    // 属性设置 当前元素transform_val 其子元素transform_val
    function css3_transform(element, value) {
        var arr_priex = ["O", "Ms", "Moz", "Webkit", ""];

        if (!!window.ActiveXObject || "ActiveXObject" in window) {
            // IE
            arr_priex = ["-O-", "-Ms-", "-Moz-", "-Webkit-", ""];
        }
        for (var i = 0; i < arr_priex.length; i += 1) {
            element.style[arr_priex[i] + "Transform"] = value;
        }
    }

    if (false !== b_update_msg) {
        // 更新模块整体信息
        update_module_msg_txt(get_module_boundary(true), true);
    }

    return true;
}

// 叠加裁剪量
function mc_addup_transform_cut(obj_target,obj_param,arr_array) {
    var arr_old_cut = mc_analysis_transform_msg(obj_target, "cut");

    if (arr_old_cut) {
        arr_old_cut = arr_old_cut.split(",");
        obj_param.cut_l += Number(arr_old_cut[0]);
        obj_param.cut_r += Number(arr_old_cut[1]);
        obj_param.cut_t += Number(arr_old_cut[2]);
        obj_param.cut_b += Number(arr_old_cut[3]);
        if (arr_array) {
            arr_array[0] += Number(arr_old_cut[0]);
            arr_array[1] += Number(arr_old_cut[1]);
            arr_array[2] += Number(arr_old_cut[2]);
            arr_array[3] += Number(arr_old_cut[3]);
            return arr_array;
        }
    }
    return [];
}
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    变换应用
 * 参数:
 *     @param {Promise<Array>} ary_mod 设置元素 jq元素数组
 *     @param {Promise<Object>} obj_data 设置参数对象 大屏连接中存在设置模块宽高字串
 *     @param {Promise<Boolean>} b_update_msg 是否更新整体模块信息; 默认更新；为false时不更新
 *     @param {Promise<Boolean>} b_splict 是否进行变换拼接
 *     @param {Promise<Object>} operate_param 操作对象
 * 返回：
 *     @returns {Promise<Boolean>}
 *      false 参数有误
 *      true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.04.08
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_rotate_scale_apply(ary_mod, obj_data, b_update_msg,b_splict,operate_param) {
    if ("[object Array]" !== Object.prototype.toString.call(ary_mod) || "[object Object]" !== Object.prototype.toString.call(obj_data)) {
        return false;
    }
    if (b_splict) {
        // 拼接变换
        // 记录移动操作信息
        operate_param.b_operate_after_move = true;
        mc_translation_apply(
            ary_mod,
            Number(obj_data.MC_LANG_ROTATION_ANGLE.val),
            [Number(obj_data.MC_LANG_X_DIRECTION.val), Number(obj_data.MC_LANG_Y_DIRECTION.val)],
            obj_data.MC_LANG_MIRROR_IMAGE.val,
            [Number(obj_data.MC_LANG_HORZ_HEAD.val),Number(obj_data.MC_LANG_HORZ_RAIL.val),Number(obj_data.MC_LANG_VERTICAL_HEAD.val),Number(obj_data.MC_LANG_VERTICAL_TAIL.val)],
            operate_param
        );
        // 更新显示信息
        update_module_msg_txt(get_module_boundary(true), true);
    } else {
        mc_transform_operate_apply(ary_mod, obj_data, b_update_msg);
    }
    return true;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    变换应用 无dom
 * 参数:
 *     @param {Promise<String>} str_id 模块id
 *     @param {Promise<Array>} arr_transform 变换数据 [scaleX,scaleY,angle,mirror,str_cut]
 *     @param {Promise<Number>} ui_grid 格子宽度
 *     @param {Promise<Array>} arr_cut 裁剪数据
 * 备注：
 *      正在初始化变换时(初始化时为单个模块变换 获取变换数据：transform属性值、transform_msg变换标识字段)
 *      1. 不更新模块整体显示信息
 *      2. 不设置模块transform_msg属性字段
 *      3. 不设置模块及其子元素transform属性
 *      4. 不设置模块偏移 变换偏差偏移
 * 返回：
 *     @returns {Promise<Object>}
 *      null 参数有误
 *      {left:左偏移值,top:右偏移值,str_transform_msg:变换标识属性值字串, str_transform_val:模块transform属性值,str_transform_child_val:子元素transform属性值}
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.02.19
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_undom_rotate_sacle_apply(str_id, arr_transform, ui_grid) {
    // 缩放大小,旋转角度
    var ui_scale_x = Number(arr_transform[0]), ui_scale_y = Number(arr_transform[1]);
    var ui_rotate_angle = Number(arr_transform[2]);
    var ui_mirror_image = Number(arr_transform[3]);
    var transform_val = "";
    var transform_child_val = "";
    // 镜像类型
    var str_mirror_type = "";
    var arr_cut = arr_transform[4] ? arr_transform[4].split(",") : [0,0,0,0];
    var transform_msg = {
        angle: ui_rotate_angle,
        scale_x: ui_scale_x,
        scale_y: ui_scale_y,
        mirror: ui_mirror_image,
        cut_l: Number(arr_cut[0]),
        cut_r: Number(arr_cut[1]),
        cut_t: Number(arr_cut[2]),
        cut_b: Number(arr_cut[3])
    };
    var obj_msg = obj_module_msg[str_id];

    if (!obj_msg) {
        return false;
    }

    if (1 === ui_mirror_image) {
        // 水平翻转
        str_mirror_type = "rotateY(180deg)translateX(-" + arr_transform[4] * ui_grid * ui_scale_x + "px) ";
        transform_child_val = "transform:rotateY(180deg);";
    }
    if (2 === ui_mirror_image) {
        // 垂直翻转
        str_mirror_type = "rotateX(180deg)translateY(-" + arr_transform[5] * ui_grid * ui_scale_y + "px) ";
        transform_child_val = "transform:rotateX(180deg);";
    }
    // transform_val = "transform:rotateZ(" + ui_rotate_angle + "deg) " + str_mirror_type + "scale3d(" + ui_scale_x + "," + ui_scale_y + "," + "1);";
    transform_val = "transform:rotateZ(" + ui_rotate_angle + "deg) " + str_mirror_type + "scale3d(1,1,1);";
    var obj_transform_msg = mc_get_rotate_crisis(false, transform_msg, obj_msg, true);

    obj_transform_msg.str_transform_val = transform_val;
    obj_transform_msg.str_transform_child_val = transform_child_val;
    return obj_transform_msg;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    拼接变换应用
* 参数:
*    @param { Promise<Object> } obj_list jq数组
*    @param { Promise<Number> } angle 旋转角度
*    @param { Promise<Array> } arr_scale 缩放参数
*    @param { Promise<String> } str_mirror 镜像
*    @param { Promise<Array> } arr_cut 裁剪大小
*    @param { Promise<Object> } operate_param 操作对象
* 返回:
*    @return { Promise<Boolean> }
*     false 参数有误
*     true 设置成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2021.04.08
*      内容 : 所有代码
************************************************************************************************/
function mc_translation_apply(obj_list, angle, arr_scale, str_mirror,arr_cut,operate_param) {
    var arr_select_offset = document.getElementsByClassName("select_msg")[0].innerText.split(":");
    // 缩放参数

    arr_scale = arr_scale || [1, 1];
    str_mirror = str_mirror || "0";
    var ui_update_w = arr_cut[0] + arr_cut[1];
    var ui_update_h = arr_cut[2] + arr_cut[3];
    var b_update_size = false;
    // 对照点坐标 -> {变换前点坐标:{obj_js: jsobject, arr_dot: 旋转后该点坐标Array},, }
    var obj_dot = {};
    // 起始点 -> {变换前点坐标:{obj_js: jsobject, arr_dot: 该元素偏移Array, arr_size: 外接矩形大小, arr_pot: 外接矩形偏移},, }
    var obj_begin_dot = {};
    var ui_scale_x = Number(arr_scale[0]);
    var ui_scale_y = Number(arr_scale[1]);
    // 镜像坐标反向设置标识
    var ui_mirror_x = "1" === str_mirror ? -1 : 1;
    var ui_mirror_y = "2" === str_mirror ? -1 : 1;
    var ui_rotate_mirror_x = ui_mirror_x;
    var ui_rotate_mirror_y = ui_mirror_y;
    var arr_origin_lefthand_offset = [Math.pow(2, 32),Math.pow(2, 32)];
    // 子元素正向显示子串
    var str_transform_child_val = "";
    var arr_move_undo = [];
    var ui_grid = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));
    var ui_offset_x = Number(arr_select_offset[1]) * (ui_scale_x - 1) * ui_grid;
    var ui_offset_y = Number(arr_select_offset[2]) * (ui_scale_y - 1) * ui_grid;
    var ary_size = [];

    if ("1" === str_mirror) {
        ui_rotate_mirror_x = ui_mirror_y;
        ui_rotate_mirror_y = ui_mirror_x;
        str_transform_child_val = "rotateY(180deg)";
    }
    // 宽高裁剪
    if (ui_update_w || ui_update_h) {
        ui_update_w *= ui_grid;
        ui_update_h *= ui_grid;
        b_update_size = true;
    }

    // 计算坐标、变换设置 ----------
    for (var i = 0; i < obj_list.length; i++) {
        var obj_target = obj_list[i][0];
        var arr_pot = [];
        var arr_mod_size = [];
        // 更改大小偏移倍数 = 原始大小/更新大小
        var ui_size_x = 1;
        var ui_size_y = 1;
        var ui_origin_w = obj_target.offsetWidth;
        var ui_origin_h = obj_target.offsetHeight;
        var obj_msg = mc_get_child_pot_size(obj_target);
        var arr_split_offset = mc_split_offset(obj_target);
        var ui_origin_l = obj_target.offsetLeft;
        var ui_origin_t = obj_target.offsetTop;
        var ui_compute_l = ui_origin_l + arr_split_offset[0];
        var ui_compute_t = ui_origin_t + arr_split_offset[1];
        var u_size_x = 0;
        var u_size_y = 0;

        arr_move_undo.push(obj_msg.str_pot.split(","));
        if (b_update_size) {
            var u_update_w = ui_origin_w - ui_update_w;
            var u_update_h = ui_origin_h - ui_update_h;

            if (0 >= u_update_w) {
                u_update_w = ui_origin_w;
                arr_cut[0] = arr_cut[1] = 0;
            }
            if (0 >= u_update_h) {
                u_update_h = ui_origin_h;
                arr_cut[2] = arr_cut[3] = 0;
            }

            arr_mod_size = [u_update_w * ui_scale_x, u_update_h * ui_scale_y];
            ui_size_x = ui_origin_w / u_update_w;
            ui_size_y = ui_origin_h / u_update_h;
            u_size_x = Number(arr_select_offset[1]) * (u_update_w / ui_origin_w - 1) * ui_scale_x * ui_grid;
            u_size_y = Number(arr_select_offset[2]) * (u_update_h / ui_origin_h - 1) * ui_scale_y * ui_grid;
            ary_size.push([u_update_w / ui_grid,u_update_h / ui_grid]);
        } else {
            arr_mod_size = [ui_origin_w * ui_scale_x, ui_origin_h * ui_scale_y];
        }
        if (0 !== i) {
            arr_pot = [ui_compute_l * ui_scale_x / ui_size_x - ui_offset_x - u_size_x, ui_compute_t * ui_scale_y / ui_size_y - ui_offset_y - u_size_y];
        } else {
            arr_pot = [ui_compute_l, ui_compute_t];
        }
        // 旋转前四点坐标 （已计算缩放）
        var arr_coordinate_result = mc_get_coordinate(arr_pot,arr_mod_size, ui_rotate_mirror_x, ui_rotate_mirror_y);
        var arr_coordinate = arr_coordinate_result[0];
        var arr_coordinate_mirroe = arr_coordinate_result[1];

        if (0 === arr_coordinate.length) {
            continue;
        }
        // 变化前模块偏移信息
        var arr_origin = arr_coordinate[0];
        var obj_coordinator = mc_compare_transform_coordinator(
            arr_coordinate,
            angle,
            arr_coordinate_mirroe,
            ui_mirror_x,
            ui_mirror_y,
            obj_dot,
            obj_target,
            arr_origin_lefthand_offset);

        obj_begin_dot[arr_origin] = {
            obj_js: obj_target,
            // 变换前位置
            arr_dot: arr_origin,
            // 外界矩形大小
            arr_size: [obj_coordinator.ui_max_x - obj_coordinator.ui_min_x, obj_coordinator.ui_max_y - obj_coordinator.ui_min_y],
            // 变换前位置(计算过缩放)
            arr_pot: arr_pot,
            // 计算过缩放的元素大小
            arr_mod_size: arr_mod_size,
            arr_origin_offset: [ui_origin_l,ui_origin_t]
        };

        // 变换设置
        mc_update_transform_matrix(
            mc_translation_matrix(
                mc_get_compute_matrix_params(angle, arr_scale, str_mirror)
            ),
            obj_target
        );
        // 显示信息正向
        mc_mirroe_showmsg_positive(obj_target,"2" === str_mirror ? "rotateX(180deg)" : str_transform_child_val);
    }

    // 计算拼接偏移量 ----------
    mc_computer_split_offset(obj_begin_dot,obj_dot);
    var arr_move_redo = mc_adjust_offset(
        obj_begin_dot,
        mc_get_adjust_offset(obj_begin_dot, str_mirror, angle),
        arr_origin_lefthand_offset,
        str_mirror,
        arr_scale,
        angle,
        ary_size.length ? ary_size : false,
        arr_cut
    );

    operate_param.obj_operate_after.undo = arr_move_undo;
    operate_param.obj_operate_after.redo = arr_move_redo;
    return true;
}

// 计算旋转后临点坐标
function mc_compare_transform_coordinator(
    arr_coordinate,
    angle,
    arr_coordinate_mirroe,
    ui_mirror_x,
    ui_mirror_y,
    obj_dot,
    obj_target,
    arr_origin_lefthand_offset) {
    var arr_origin = arr_coordinate[0];
    var ui_min_x = arr_origin[0];
    var ui_min_y = arr_origin[1];
    var ui_max_x = arr_origin[0];
    var ui_max_y = arr_origin[1];

    for (var idx = 1; idx < arr_coordinate.length; idx++) {
        var arr_result = mc_rotate_coordinate(arr_origin, arr_coordinate[idx], angle, arr_coordinate_mirroe[idx], ui_mirror_x, ui_mirror_y);
        var arr_dot = arr_result[1];
        var ui_rotate_x = arr_dot[0];
        var ui_rotate_y = arr_dot[1];

        // 保存对照坐标
        obj_dot[arr_coordinate[idx]] = {
            obj_js: obj_target,
            arr_dot: arr_result[0]
        };
        if (ui_min_x > ui_rotate_x) {
            ui_min_x = ui_rotate_x;
        }
        if (ui_min_y > ui_rotate_y) {
            ui_min_y = ui_rotate_y;
        }
        if (ui_max_x < ui_rotate_x) {
            ui_max_x = ui_rotate_x;
        }
        if (ui_max_y < ui_rotate_y) {
            ui_max_y = ui_rotate_y;
        }
    }

    if (arr_origin[0] < arr_origin_lefthand_offset[0]) {
        arr_origin_lefthand_offset[0] = arr_origin[0];
    }
    if (arr_origin[1] < arr_origin_lefthand_offset[1]) {
        arr_origin_lefthand_offset[1] = arr_origin[1];
    }
    return {
        ui_min_x: ui_min_x,
        ui_min_y: ui_min_y,
        ui_max_x: ui_max_x,
        ui_max_y: ui_max_y
    };
}

// 计算拼接偏移量
function mc_computer_split_offset(obj_begin_dot,obj_dot) {
    var arr_key = Object.keys(obj_begin_dot);
    var index = 0;
    var obj_chg = {};

    while (index < arr_key.length) {
        var str_key = arr_key[index++];
        var obj_origin_data = obj_begin_dot[str_key];
        var obj_origin_target = obj_origin_data.obj_js;

        if (obj_dot[str_key] && 1 !== obj_dot[str_key].arr_dot && obj_dot[str_key].obj_js !== obj_origin_target) {
            var str_id = obj_dot[str_key].obj_js.id;
            // 外接矩形坐标
            // var arr_cs_pot = obj_origin_data.arr_pot;
            var arr_cs_pot = $.extend(true,[],obj_origin_data.arr_pot);
            var ui_chg_l = 0;
            var ui_chg_t = 0;

            if (obj_chg[str_id]) {
                ui_chg_l = obj_chg[str_id][0];
                ui_chg_t = obj_chg[str_id][1];
            }
            obj_chg[obj_origin_target.id] = [obj_dot[str_key].arr_dot[0] + ui_chg_l - obj_origin_data.arr_dot[0], obj_dot[str_key].arr_dot[1] + ui_chg_t - obj_origin_data.arr_dot[1]];
            // 修改偏移后外接偏移位置
            // arr_cs_pot[0] = obj_dot[str_key].arr_dot[0] + ui_chg_l;
            // arr_cs_pot[1] = obj_dot[str_key].arr_dot[1] + ui_chg_t;
            obj_origin_data.arr_pot[0] = obj_dot[str_key].arr_dot[0] + ui_chg_l;
            obj_origin_data.arr_pot[1] = obj_dot[str_key].arr_dot[1] + ui_chg_t;
            // // 继续变换时位置差值
            // obj_origin_target.setAttribute("split_x",Math.round(arr_cs_pot[0] - obj_origin_data.arr_pot[0]));
            // obj_origin_target.setAttribute("split_y",Math.round(arr_cs_pot[1] - obj_origin_data.arr_pot[1]));
        }
    }
    return true;
}

// 获取整体外接矩形左上角位置 计算矫正偏移量
function mc_get_adjust_offset(obj_data, str_mirror, angle) {
    var arr_key = Object.keys(obj_data);
    var ui_min_left = Math.pow(2, 32);
    var ui_min_top = Math.pow(2, 32);
    var radian = (angle) / 360.0 * 2 * Math.PI;
    var radian2 = (90 - angle) / 360.0 * 2 * Math.PI;
    var radian3 = (180 - angle) / 360.0 * 2 * Math.PI;

    for (var i = 0; i < arr_key.length; i++) {
        var obj_item = obj_data[arr_key[i]];
        var arr_pot = obj_item.arr_pot;
        var arr_size = obj_item.arr_size;
        var ui_l = arr_pot[0];
        var ui_t = arr_pot[1];
        var ui_h = obj_item.arr_mod_size[1];

        obj_item.arr_offset_dif = [];

        if ("0" === str_mirror) {
            if (90 < angle) {
                obj_item.arr_offset_dif[0] = arr_size[0];
                obj_item.arr_offset_dif[1] = ui_h * Math.cos(radian3);
                if (ui_min_left > ui_l - arr_size[0]) {
                    ui_min_left = ui_l - arr_size[0];
                }
                if (ui_min_top > ui_t - obj_item.arr_offset_dif[1]) {
                    ui_min_top = ui_t - obj_item.arr_offset_dif[1];
                }
            } else {
                obj_item.arr_offset_dif[0] = ui_h * Math.cos(radian2);
                obj_item.arr_offset_dif[1] = 0;
                if (ui_min_left > ui_l - obj_item.arr_offset_dif[0]) {
                    ui_min_left = ui_l - obj_item.arr_offset_dif[0];
                }
                if (ui_min_top > ui_t) {
                    ui_min_top = ui_t;
                }
            }
        }
        // 左右
        if ("1" === str_mirror) {
            if (90 < angle) {
                obj_item.arr_offset_dif[0] = ui_h * Math.cos(radian2);
                obj_item.arr_offset_dif[1] = arr_size[1];
                if (ui_min_left > ui_l - obj_item.arr_offset_dif[0]) {
                    ui_min_left = ui_l - obj_item.arr_offset_dif[0];
                }
                if (ui_min_top > ui_t - arr_size[1]) {
                    ui_min_top = ui_t - arr_size[1];
                }
            } else {
                obj_item.arr_offset_dif[0] = arr_size[0];
                obj_item.arr_offset_dif[1] = arr_size[1] - ui_h * Math.cos(radian);
                if (ui_min_left > ui_l - arr_size[0]) {
                    ui_min_left = ui_l - arr_size[0];
                }
                if (ui_min_top > ui_t + ui_h * Math.cos(radian) - arr_size[1]) {
                    ui_min_top = ui_t + ui_h * Math.cos(radian) - arr_size[1];
                }
            }
        }
        // 上下
        if ("2" === str_mirror) {
            if (90 < angle) {
                obj_item.arr_offset_dif[0] = obj_item.arr_mod_size[0] * Math.cos(radian3);
                obj_item.arr_offset_dif[1] = 0;
                if (ui_min_left > ui_l - obj_item.arr_offset_dif[0]) {
                    ui_min_left = ui_l - obj_item.arr_offset_dif[0];
                }
                if (ui_min_top > ui_t) {
                    ui_min_top = ui_t;
                }
            } else {
                obj_item.arr_offset_dif[0] = 0;
                obj_item.arr_offset_dif[1] = ui_h * Math.cos(radian);
                if (ui_min_left > ui_l) {
                    ui_min_left = ui_l;
                }
                if (ui_min_top > ui_t - obj_item.arr_offset_dif[1]) {
                    ui_min_top = ui_t - obj_item.arr_offset_dif[1];
                }
            }
        }
    }
    return [ui_min_left, ui_min_top];
}

// 调整偏移 左上角与变换前左上角位置相等 、 更新元素变换参数信息 transform_msg字串、更新模块大小偏移信息,裁剪数值
function mc_adjust_offset(obj_data, arr_lefthand_offset, arr_origin_lefthand_offset, str_mirror, arr_scale, angle,ary_size,arr_cut) {
    // 格子宽度
    var ui_grid = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));
    var arr_key = Object.keys(obj_data);
    // 偏移坐标
    var ui_adjust_x = arr_origin_lefthand_offset[0] - arr_lefthand_offset[0];
    var ui_adjust_y = arr_origin_lefthand_offset[1] - arr_lefthand_offset[1];
    var ui_scale_x = Number(arr_scale[0]);
    var ui_scale_y = Number(arr_scale[1]);
    var arr_move_redo = [];

    // arr_size = arr_size ? [Number(arr_size[0]) * ui_scale_x,Number(arr_size[1]) * ui_scale_y] : false;
    for (var i = 0; i < arr_key.length; i++) {
        var obj_item = obj_data[arr_key[i]];
        var obj_js = obj_item.obj_js;
        var arr_pot = obj_item.arr_pot;
        var ui_adjust_grid_x = obj_item.arr_offset_dif[0];
        var ui_adjust_grid_y = obj_item.arr_offset_dif[1];
        var obj_msg = mc_get_child_pot_size(obj_js);
        var ui_x_grid = Math.round((arr_pot[0] + ui_adjust_x - ui_adjust_grid_x) / ui_grid);
        var ui_y_grid = Math.round((arr_pot[1] + ui_adjust_y - ui_adjust_grid_y) / ui_grid);
        var arr_size = ary_size[i] ? [Number(ary_size[i][0]) * ui_scale_x,Number(ary_size[i][1]) * ui_scale_y] : false;

        // 箱体连接
        if (!arr_size) {
            arr_size = [ Math.round(obj_item.arr_mod_size[0] / ui_grid) , Math.round(obj_item.arr_mod_size[0] / ui_grid)];
        }
        arr_move_redo.push([ui_x_grid,ui_y_grid]);
        // 更新元素变换参数信息
        arr_cut = mc_addup_transform_cut(obj_js,false,arr_cut);
        obj_js.setAttribute("transform_msg",
            Math.round(obj_item.arr_size[0] / ui_grid) + "," + Math.round(obj_item.arr_size[1] / ui_grid) + "," +
                        Math.round(ui_adjust_grid_x / ui_grid) + "," +
                        Math.round(ui_adjust_grid_y / ui_grid) + "_" +
                        angle + "_" + ui_scale_x + "," + ui_scale_y + "_" + str_mirror + "_" +
                        (arr_cut[0]||0) + "," + (arr_cut[1]||0) + "," + (arr_cut[2]||0) + "," + (arr_cut[3]||0)
        );

        // 更新存储模块信息
        obj_js.setAttribute("mod_wg",arr_size[0]);
        obj_js.setAttribute("mod_hg",arr_size[1]);
        // 更新显示信息
        obj_msg.o_pot.innerText = ui_x_grid + "," + ui_y_grid;
        obj_msg.o_size.innerText = arr_size[0] + "X" + arr_size[1];
        mc_update_module_msg(obj_js.id, ui_x_grid + "," + ui_y_grid, arr_size[0] + "X" + arr_size[1]);
        // 更新大小偏移
        obj_js.style.left = arr_pot[0] + ui_adjust_x + "px";
        obj_js.style.top = arr_pot[1] + ui_adjust_y + "px";
        obj_js.style.width = arr_size[0] * ui_grid + "px";
        obj_js.style.height = arr_size[1] * ui_grid + "px";
        obj_js.setAttribute("split_x",Math.round(obj_item.arr_origin_offset[0] - (arr_pot[0] + ui_adjust_x)));
        obj_js.setAttribute("split_y",Math.round(obj_item.arr_origin_offset[1] - (arr_pot[1] + ui_adjust_y)));
    }
    return arr_move_redo;
}

// 之前拼接变换偏移量
function mc_split_offset(obj_js) {
    if ("[OBJECT HTMLDIVELEMENT]" !== Object.prototype.toString.call(obj_js).toUpperCase()) {
        return [0,0];
    }
    var ui_split_x = Number(obj_js.getAttribute("split_x"));
    var ui_split_y = Number(obj_js.getAttribute("split_y"));

    if (!isNaN (ui_split_x) && !isNaN(ui_split_y)) {
        obj_js.removeAttribute("split_x");
        obj_js.removeAttribute("split_y");
        return [ui_split_x,ui_split_y];
    }
    return [0,0];
}

// 变换功能函数-----------------------------------------------------------------------------------
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    记录旋转后transform_msg 更新外接矩形偏移
 * 参数:
 *     @param {Promise<Object>} obj_target 当前元素 js
 *     @param {Promise<Object>} obj_transform_msg 变化信息
 *     @param {Promise<Object>} obj_msg 模块数据对象
 *     @param {Promise<Boolean>} b_set_transform 是否设置变换属性 true不设置 可为空默认设置
 * 返回：
 *     @returns {Promise<Object>}
 *      {str_transform_msg: transform_msg字串,left: 变换后偏移left,top: 变换后偏移top}
 *      null 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.10.17
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_rotate_crisis(obj_target, obj_transform_msg, obj_msg, b_set_transform) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target) && !b_set_transform) {
        return null;
    }
    if ("[object Object]" !== Object.prototype.toString.call(obj_transform_msg)) {
        return null;
    }
    var ui_rotate_angle = Number(obj_transform_msg.angle);
    var ui_scale_x = Number(obj_transform_msg.scale_x);
    var ui_scale_y = Number(obj_transform_msg.scale_y);

    if (!obj_msg) {
        return false;
    }
    // 获取旋转前元素临点坐标（此处为缩放后）
    var arr_pot = obj_msg.str_pot.split(",");
    var arr_size = obj_msg.str_size.split("X");
    var arr_coordinate = mc_get_coordinate(arr_pot, arr_size)[0];

    if (0 === arr_coordinate.length) {
        return false;
    }
    // 变化前模块偏移信息
    var arr_origin = arr_coordinate[0];
    // 最小left/top为旋转后位置
    var ui_min_x = arr_origin[0];
    var ui_min_y = arr_origin[1];
    var ui_max_x = arr_origin[0];
    var ui_max_y = arr_origin[1];

    // 计算旋转后临点坐标
    for (var idx = 1; idx < arr_coordinate.length; idx++) {
        var arr_dot = arr_coordinate[idx];

        arr_dot = mc_rotate_coordinate(arr_origin, arr_dot, ui_rotate_angle);
        var ui_rotate_x = arr_dot[0];
        var ui_rotate_y = arr_dot[1];

        if (ui_min_x > ui_rotate_x) {
            ui_min_x = ui_rotate_x;
        }
        if (ui_min_y > ui_rotate_y) {
            ui_min_y = ui_rotate_y;
        }
        if (ui_max_x < ui_rotate_x) {
            ui_max_x = ui_rotate_x;
        }
        if (ui_max_y < ui_rotate_y) {
            ui_max_y = ui_rotate_y;
        }
    }

    // 记录外界矩形大小
    var ui_rotate_w = Math.round((ui_max_x - ui_min_x));
    var ui_rotate_h = Math.round((ui_max_y - ui_min_y));
    var str_transform_msg = "";

    // if (0 === ui_rotate_angle && 1 === ui_scale_x && 1 === ui_scale_y && 0 === obj_transform_msg.mirror) {
    //     if (!b_set_transform) {
    //         obj_target.removeAttribute("transform_msg");
    //     }
    // } else {
    // 缩放参数保留一位小数
    var arr_scale = mc_format_scale_param([ui_scale_x, ui_scale_y]);

    if (arr_scale) {
        ui_scale_x = arr_scale[0];
        ui_scale_y = arr_scale[1];
    }
    // transform_msg信息格子数 : 当前元素W,H,矫正偏移量L,矫正偏移量T _ 旋转角度 _ XY缩放倍数 _ 镜像_左裁剪,右裁剪,上裁剪,下裁剪
    str_transform_msg = ui_rotate_w + "," + ui_rotate_h + "," + Math.round((arr_origin[0] - ui_min_x)) + "," + Math.round((arr_origin[1] - ui_min_y)) + "_" + ui_rotate_angle + "_" + ui_scale_x + "," + ui_scale_y + "_"
    + obj_transform_msg.mirror + "_" + obj_transform_msg.cut_l + "," + obj_transform_msg.cut_r + "," + obj_transform_msg.cut_t + "," + obj_transform_msg.cut_b;

    if (!b_set_transform) {
        obj_target.setAttribute("transform_msg", str_transform_msg);
    }
    // }

    // 修改偏移 外界矩形LT为变化前LT
    var ui_offset_l = 2 * arr_origin[0] - ui_min_x;
    var ui_offset_t = 2 * arr_origin[1] - ui_min_y;

    if (!b_set_transform) {
        var ui_grid_w = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));

        obj_target.style.left = ui_offset_l * ui_grid_w + "px";
        obj_target.style.top = ui_offset_t * ui_grid_w + "px";
    }

    return {
        str_transform_msg: str_transform_msg,
        left: ui_offset_l,
        top: ui_offset_t
    };
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取未旋转前矩形元素四点坐标
 * 参数:
 *     @param {Promise<Array>} arr_pot 元素位置格子数
 *     @param {Promise<Array>} arr_size 元素大小格子数 x X y 初始化
 *     @param {Promise<Number>} ui_mirror_x 镜像计算参数 1/-1
 *     @param {Promise<Number>} ui_mirror_y
 * 返回：
 *     @returns {Promise<Array>}
 *      arr_coordinate 对应四点坐标
 *      false 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.10.21
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_get_coordinate( arr_pot, arr_size,ui_mirror_x,ui_mirror_y) {
    if ("[object Array]" !== Object.prototype.toString.call(arr_pot)) {
        return false;
    }
    var arr_coordinate = [];
    var arr_mirroe = [];
    var ui_x = Number(arr_pot[0]);
    var ui_y = Number(arr_pot[1]);
    var ui_w = Number(arr_size[0]);
    var ui_h = Number(arr_size[1]);

    arr_coordinate[0] = [ui_x, ui_y];
    arr_coordinate[1] = [ui_x + ui_w, ui_y];
    arr_coordinate[2] = [ui_x, ui_y + ui_h];
    arr_coordinate[3] = [ui_x + ui_w, ui_y + ui_h];

    if (ui_mirror_x && ui_mirror_y ) {
        arr_mirroe[0] = [ui_x, ui_y];
        arr_mirroe[1] = [ui_x + ui_w * ui_mirror_y, ui_y];
        arr_mirroe[2] = [ui_x, ui_y + ui_h * ui_mirror_x];
        arr_mirroe[3] = [ui_x + ui_w * ui_mirror_y, ui_y + ui_h * ui_mirror_x];
        // return [arr_coordinate,arr_mirroe];
    }
    return [arr_coordinate,arr_mirroe];
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    计算旋转后新坐标值
 * 参数:
 *     @param {Promise<Array>} arr_origin 旋转基点坐标
 *     @param {Promise<Array>} arr_coordinate 计算点坐标
 *     @param {Promise<Number>} ui_rotate_angle 旋转角度
 *     @param {Promise<Array>} arr_mirroe_coordinate 镜像点
 *     @param {Promise<Number>} ui_mirror_x 镜像计算参数 1/-1
 *     @param {Promise<Number>} ui_mirror_y
 * 返回：
 *     @returns {Promise<Array>}
 *      arr_result 新坐标值[x,y]
 *      false 参数有误
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2020.10.21
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_rotate_coordinate(arr_origin, arr_coordinate, ui_rotate_angle,arr_mirroe_coordinate,ui_mirror_x, ui_mirror_y) {
    if ("[object Array]" !== Object.prototype.toString.call(arr_origin) || "[object Array]" !== Object.prototype.toString.call(arr_coordinate) || "[object Number]" !== Object.prototype.toString.call(ui_rotate_angle)) {
        return false;
    }
    var arr_result = [];
    var arr_mirror = [];
    var ui_xo = Number(arr_origin[0]);
    var ui_yo = Number(arr_origin[1]);
    var ui_x = Number(arr_coordinate[0]);
    var ui_y = Number(arr_coordinate[1]);
    var cosVal = Math.cos(ui_rotate_angle * Math.PI / 180), sinVal = Math.sin(ui_rotate_angle * Math.PI / 180);


    arr_result[0] = (ui_x - ui_xo) * cosVal - (ui_y - ui_yo) * sinVal + ui_xo;
    arr_result[1] = (ui_x - ui_xo) * sinVal + (ui_y - ui_yo) * cosVal + ui_yo;

    if (ui_mirror_x && ui_mirror_y && arr_mirroe_coordinate) {
        var cosVal_mirror = Math.cos(ui_rotate_angle * Math.PI / 180) * ui_mirror_x, sinVal_mirroe = Math.sin(ui_rotate_angle * Math.PI / 180) * ui_mirror_y;

        ui_x = Number(arr_mirroe_coordinate[0]);
        ui_y = Number(arr_mirroe_coordinate[1]);
        arr_mirror[0] = (ui_x - ui_xo) * cosVal_mirror - (ui_y - ui_yo) * sinVal_mirroe + ui_xo;
        arr_mirror[1] = (ui_x - ui_xo) * sinVal_mirroe + (ui_y - ui_yo) * cosVal_mirror + ui_yo;
        return [arr_result,arr_mirror];
    }
    return arr_result;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    判断是否为变化元素 若是返回外接元素偏移格子数 否则返回当前偏移格子数
* 参数:
*    @param { Promise<Object> } obj_target js
*    @param { Promise<Number/Boolean> } ui_x 模组X格子数
*    @param { Promise<Number/Boolean> } ui_y 模组Y格子数
*    @param { Promise<Number> } ui_update_x 模组当前显示格子数
*    @param { Promise<Number> } ui_update_y 模组当前显示格子数
* 返回：
*    @return { Promise<String> }
*     false 参数有误
*     true 更新成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.10.19
*      内容 : 所有代码
************************************************************************************************/
function judge_transform_mod_pot(obj_target, ui_x, ui_y, ui_update_x, ui_update_y) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target) || "[object Number]" !== Object.prototype.toString.call(ui_update_x) || "[object Number]" !== Object.prototype.toString.call(ui_update_y)) {
        return false;
    }
    var arr_msg = mc_analysis_transform_msg(obj_target);
    var ui_grid_w = 1;
    var b_computer_x = true;
    var b_computer_y = true;

    if ("[object Number]" !== Object.prototype.toString.call(ui_x)) {
        ui_x = ui_update_x;
        b_computer_x = false;
    }
    if ("[object Number]" !== Object.prototype.toString.call(ui_y)) {
        ui_y = ui_update_y;
        b_computer_y = false;
    }

    if (arr_msg) {
        ui_grid_w = document.getElementById("mod_box_next").getAttribute("grid_w");
        ui_grid_w = Number(ui_grid_w);

        if (b_computer_x) {
            ui_x = (ui_x * ui_grid_w - Number(arr_msg[2])) / ui_grid_w;
        }
        if (b_computer_y) {
            ui_y = (ui_y * ui_grid_w - Number(arr_msg[3])) / ui_grid_w;
        }
    }
    return Math.round(ui_x) + "," + Math.round(ui_y);
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    解析元素transform_msg字串信息 获得对应数据 实际长度
* 参数:
*    @param { Promise<Object> } obj_target js
*    @param { Promise<String> } str_type 获取信息类型 可为空默认获取外界矩形信息[W,H,Lc,Tc] "angle"-旋转角度 "scale"-[缩放倍数] "mirror"-镜像 "all"-所有 返回数组
*    @param { Promise<Boolean> } b_send_get 简易模式下 "all"类型 获取变换信息 可为空
*备注:
*      外界矩形信息[W,H,Lc,Tc] => [外接矩形宽度,外接矩形高度,外接矩形相对于变化模块L偏移(获取外接矩形偏移 应用变化模块偏移减去此值),外接矩形相对于变化模块T偏移]
*      str_type === 'all' 返回 [[W,H,Lc,Tc], "angle", [缩放倍数X, 缩放倍数Y], "镜像"]
* 返回:
*    @return { Promise<Array> }
*     false 参数有误 /不存在transform_msg字串
*     arr_result 对应数据数组
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.10.19
*      内容 : 所有代码
************************************************************************************************/
function mc_analysis_transform_msg(obj_target, str_type, b_send_get) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target)) {
        return false;
    }
    var str_transform_msg = obj_target.getAttribute("transform_msg");

    // 获取变换信息字串
    if (obj_item_checkbox_easy_mode.get_dom_val() && "all" === str_type && b_send_get) {
        var str_transform_json = obj_target.getAttribute("str_trans");

        if ("string" !== typeof str_transform_json || 0 === str_transform_json.length) {
            return false;
        }
        var obj_trans = JSON.parse(str_transform_json);
        var ui_scale_x = Number(obj_trans.MC_LANG_X_DIRECTION.val), ui_scale_y = Number(obj_trans.MC_LANG_Y_DIRECTION.val);
        var ui_rotate_angle = Number(obj_trans.MC_LANG_ROTATION_ANGLE.val);
        var ui_mirror_image = Number(obj_trans.MC_LANG_MIRROR_IMAGE.val);

        str_transform_msg = "0,0,0,0" + "_" + ui_rotate_angle + "_" + ui_scale_x + "," + ui_scale_y + "_" + ui_mirror_image;
    }

    if ("string" !== typeof str_transform_msg || 0 === str_transform_msg.length) {
        return false;
    }
    var arr_msg = str_transform_msg.split("_");
    var arr_result = [];
    var arr_scale = [];

    if (!str_type) {
        arr_result = arr_msg[0].split(",");
        arr_result = get_compute(arr_result);
        return arr_result;
    }

    switch (str_type) {
    case "angle":
        arr_result = arr_msg[1];
        break;
    case "scale":
        arr_scale = arr_msg[2].split(",");
        arr_result = mc_format_scale_param(arr_scale) || arr_scale;
        break;
    case "mirror":
        arr_result = arr_msg[3];
        break;
    case "cut":
        arr_result = arr_msg[4] || "0,0,0,0";
        break;
    case "all":
        arr_scale = arr_msg[2].split(",");
        arr_result.push(get_compute(arr_msg[0].split(",")));
        arr_result.push(arr_msg[1]);
        arr_result.push(mc_format_scale_param(arr_scale) || arr_scale);
        arr_result.push(arr_msg[3]);
        arr_result.push(arr_msg[4] || "0,0,0,0");
        break;
    default:
        break;
    }

    // 获取计算格子宽度后实际长度数组
    function get_compute(ary_msg) {
        if ("[object Array]" !== Object.prototype.toString.call(ary_msg)) {
            return false;
        }

        var ui_grid_w = document.getElementById("mod_box_next").getAttribute("grid_w");

        ui_grid_w = Number(ui_grid_w);
        for (var idx = 0; idx < ary_msg.length; idx++) {
            var ui_item = Number(ary_msg[idx]);

            ary_msg[idx] = String(ui_item * ui_grid_w);
        }
        return ary_msg;
    }

    return arr_result;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    格式化缩放参数为带一位小数
* 参数:
*    @param { Promise<Array> } ary_scale [scale_x, scale_y]
* 返回:
*    @return { Promise<Array> }
*     false 参数有误
*     ary_scale 格式化后缩放参数数组
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2021.01.12
*      内容 : 所有代码
************************************************************************************************/
function mc_format_scale_param(ary_scale) {
    if ("[object Array]" !== Object.prototype.toString.call(ary_scale)) {
        return false;
    }
    for (var idx = 0; idx < ary_scale.length; idx++) {
        var str_item = String(ary_scale[idx]);

        if (-1 === str_item.indexOf(".")) {
            ary_scale[idx] = str_item + ".0";
        }
    }
    return ary_scale;
}

/************************************************************************************************
* 类型:
*    函数
* 功能:
*    获取元素偏移/大小 外接矩形
* 参数:
*    @param { Promise<Object> } obj_target js
*    @param { Promise<Boolean> } b_get_size true获取大小 可为空默认获取偏移信息
*    @param { Promise<Boolean> } b_boundbox_offset 是否获取与外接矩形偏移差 可为空 获取大小时默认获取/获取偏移时需传入ture 即可获取
* 返回：
*    @return { Promise<Array> }
*     获取对应数组 [number:width, number:height,number:模块与外接矩形L偏移差,number:T偏移差] / [number:left, number:top,number:模块与外接矩形L偏移差,number:T偏移差] 结果计算过格子宽度
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2020.10.19
*      内容 : 所有代码
*   2. 类型 : 添加
*      作者 : 巫昭雯
*      时间 : 2020.11.26
*      内容 : 简易模式 obj_item_checkbox_easy_mode.get_dom_val() === true 时框选返回模块的大小位置数据（使用offset值）
************************************************************************************************/
function mc_get_optsize_msg(obj_target, b_get_size, b_boundbox_offset) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target)) {
        return false;
    }
    var ui_grid_w = 1;
    var arr_result = [];
    var arr_msg = [];

    ui_grid_w = document.getElementById("mod_box_next").getAttribute("grid_w");
    ui_grid_w = Number(ui_grid_w);
    //  / ui_mod_box_scale / 100


    if (b_get_size) {
        // size
        arr_msg = mc_analysis_transform_msg(obj_target);

        if (arr_msg) {
            arr_result.push(Number(arr_msg[0]), Number(arr_msg[1]), Math.round(arr_msg[2]), Math.round(arr_msg[3]));
        } else {
            // var size_wh = mc_get_child_pot_size(obj_target).o_size.innerText;
            var size_wh = mc_get_child_pot_size(obj_target).str_size;

            if (obj_item_checkbox_easy_mode.get_dom_val() || -1 === size_wh.indexOf("X")) {
                arr_result.push(obj_target.offsetWidth, obj_target.offsetHeight, 0, 0);
            } else {
                // if (-1 !== size_wh.indexOf("X")) {
                size_wh = size_wh.split("X");
                arr_result.push(Number(size_wh[0]) * ui_grid_w, Number(size_wh[1]) * ui_grid_w, 0, 0);
                // } else {
                //     arr_result.push(obj_target.offsetWidth,obj_target.offsetHeight,0,0);
                // }
            }
        }
        return arr_result;
    }

    // position
    // var offset_xy = mc_get_child_pot_size(obj_target).o_pot.innerText;
    var offset_xy = mc_get_child_pot_size(obj_target).str_pot;

    if (obj_item_checkbox_easy_mode.get_dom_val() || -1 === offset_xy.indexOf(",")) {
        arr_result.push(obj_target.offsetLeft, obj_target.offsetTop, 0, 0);
    } else {
        // if (-1 !== offset_xy.indexOf(",")) {
        offset_xy = offset_xy.split(",");
        arr_result.push(Number(offset_xy[0]) * ui_grid_w, Number(offset_xy[1]) * ui_grid_w, 0, 0);
        // } else {
        //     arr_result.push(obj_target.offsetLeft,obj_target.offsetTop,0,0);
        // }
    }

    if (b_boundbox_offset) {
        arr_msg = mc_analysis_transform_msg(obj_target);

        if (arr_msg) {
            arr_result[2] = Math.round(arr_msg[2]);
            arr_result[3] = Math.round(arr_msg[3]);
        }
    }
    return arr_result;
}

// 拼接变换功能函数---------------------------
/************************************************************************************************
* 类型:
*    函数
* 功能:
*    显示信息正向设置
* 参数:
*    @param { Promise<Object> } obj_target js
*    @param { Promise<String> } str_transform 子元素正向设置字串
* 返回:
*    @return { Promise<Boolean> }
*     false 参数有误
*     true 设置成功
* 修改:
*   1. 类型 : 创建
*      作者 : 陈小荟
*      时间 : 2021.04.08
*      内容 : 所有代码
************************************************************************************************/
function mc_mirroe_showmsg_positive(obj_target,str_transform) {
    if ("[object HTMLDivElement]" !== Object.prototype.toString.call(obj_target)) {
        return false;
    }
    if ("[object String]" !== Object.prototype.toString.call(str_transform) || 0 === str_transform.length) {
        return false;
    }
    // 显示信息正向
    var child_list = obj_target.childNodes;
    var child_msg_list = child_list[0].childNodes;

    for (var idx_child = 0; idx_child < child_msg_list.length; idx_child++) {
        var obj_child = child_msg_list[idx_child];

        css3_transform(obj_child, str_transform);
    }
    css3_transform(child_list[1].childNodes[0], str_transform);
    css3_transform(child_list[2].childNodes[0], str_transform);
    if (!b_create_grid) {
        // 卡下标
        css3_transform(child_list[3].childNodes[0], str_transform);
    }
    return true;

    // 属性设置 当前元素transform_val 其子元素transform_val
    function css3_transform(element, value) {
        var arr_priex = ["O", "Ms", "Moz", "Webkit", ""];

        if (!!window.ActiveXObject || "ActiveXObject" in window) {
            // IE
            arr_priex = ["-O-", "-Ms-", "-Moz-", "-Webkit-", ""];
        }
        for (var i = 0; i < arr_priex.length; i += 1) {
            element.style[arr_priex[i] + "Transform"] = value;
        }
    }
}

// 更新transform matrix3d
function mc_update_transform_matrix(translation_matrix, obj_js) {
    var str_matrix = "";

    for (var i = 0, len = translation_matrix.length; i < len; i++) {
        var row = translation_matrix[i];

        for (var j = 0, jlen = row.length; j < jlen; j++) {
            str_matrix += translation_matrix[i][j] + ",";
        }
    }
    obj_js.style.transform = "matrix3d(" + str_matrix.substr(0, str_matrix.length - 1) + ")";
    return true;
}

// 获取参数对象
// str_mirror => "2" === 左右(绕Y轴) "1" === 上下(绕X轴)
function mc_get_compute_matrix_params(ui_angle, arr_scale, str_mirror) {
    var obj_param = {
        rotate_base_pnt: [0, 0],
        rotate_vector: [0, 0],
        rotate_angle: ui_angle,
        scale_base_pnt: [0, 0],
        scale_val: arr_scale || [1.0, 1.0],
        offset: [0, 0],
        mirror_base_pnt: [0, 0],
        mirror_vector: false,
        mirror_angle: false
    };
    var radian = 0;

    if ("2" === str_mirror) {
        radian = (180) / 360.0 * 2 * Math.PI;

        obj_param.mirror_vector = [Math.sin(radian), 0];
        obj_param.mirror_angle = 180;
    }

    if ("1" === str_mirror) {
        radian = (180) / 360.0 * 2 * Math.PI;

        obj_param.mirror_vector = [0, -Math.sin(radian)];
        obj_param.mirror_angle = 180;
    }
    return obj_param;
}

// 变换matrix3D矩阵计算---------------------------
// 矩阵乘积
function mc_matrix_multiply(martrix_m, martrix_n) {
    if ("[object Array]" !== Object.prototype.toString.call(martrix_m) || 0 === martrix_m.length) {
        return false;
    }
    if ("[object Array]" !== Object.prototype.toString.call(martrix_n) || 0 === martrix_n.length) {
        return false;
    }
    // 矩阵是否可相乘条件:矩阵一的列数 = 矩阵二的行数
    if (martrix_m[0].length !== martrix_n.length) {
        return false;
    }
    var result_martrix = [];

    for (var i = 0, len = martrix_m.length; i < len; i++) {
        // 行
        var m_row = martrix_m[i];

        result_martrix[i] = [];
        for (var j = 0, jlen = martrix_n.length; j < jlen; j++) {
            var result_rowcol = 0;

            // 如果n矩阵没有足够的列数相乘，转入m矩阵下一行
            if ("[object Undefined]" === Object.prototype.toString.call(get_rowcol_data(martrix_n, 0, j))) {
                break;
            }
            for (var k = 0, kLen = jlen; k < kLen; k++) {
                result_rowcol += m_row[k] * get_rowcol_data(martrix_n, k, j);
            }
            result_martrix[i][j] = result_rowcol;
        }
    }

    return result_martrix;

    // 获取矩阵对应位置数据 matrix row col
    function get_rowcol_data(data, row_index, col_index) {
        if (data && data[row_index]) {
            return data[row_index][col_index];
        }
        return null;
    }
}

// 计算matrix3D矩阵
function mc_translation_matrix(
    // 旋转基准点[x,y]
    // rotate_base_pnt,
    // // 旋转向量 [p',q']
    // rotate_vector,
    // // 旋转角度 angle
    // rotate_angle,
    // // 缩放基准点 [x,y]
    // scale_base_pnt,
    // // 缩放向量[p',q'] 具体缩放值
    // scale_val,
    // // 偏移
    // offset,
    // // 镜像
    // mirror_vector,
    // mirror_angle
    param
) {
    var rotate_base_pnt = param.rotate_base_pnt;
    var rotate_vector = param.rotate_vector;
    var rotate_angle = param.rotate_angle;
    var scale_base_pnt = param.scale_base_pnt;
    // var scale_val = param.scale_val;
    var scale_val = [1,1];
    var offset = param.offset;
    var mirror_vector = param.mirror_vector;
    var mirror_angle = param.mirror_angle;
    var mirror_base_pnt = param.mirror_base_pnt;

    // result Matrix
    var translation_matrix = get_init_matrix();

    // calculate offset
    if ("[object Array]" === Object.prototype.toString.call(offset) && 2 === offset.length) {
        var offset_matrix = get_init_matrix();

        offset_matrix[3][0] = offset[0];
        offset_matrix[3][1] = offset[1];
        translation_matrix = mc_matrix_multiply(translation_matrix, offset_matrix);
    }


    // calculate scale
    if ("[object Array]" === Object.prototype.toString.call(scale_val) && 2 === scale_val.length && (1.0 !== scale_val[0] || 1.0 !== scale_val[1])) {
        var scale_matrix = get_init_matrix();

        scale_matrix[0][0] = scale_val[0];
        scale_matrix[1][1] = scale_val[1];
        if ("[object Array]" === Object.prototype.toString.call(scale_base_pnt) && 2 === scale_base_pnt.length) {
            scale_matrix[0][3] = (1 - scale_val[0]) * scale_base_pnt[0];
            scale_matrix[1][3] = (1 - scale_val[1]) * scale_base_pnt[1];
        }

        translation_matrix = mc_matrix_multiply(translation_matrix, scale_matrix);
    }

    // calculate mirror
    var rotate_matrix = calculate_rotate(mirror_angle, mirror_base_pnt, mirror_vector);

    if (0 !== rotate_matrix.length) {
        translation_matrix = mc_matrix_multiply(translation_matrix, rotate_matrix);
    }

    // calculate rotation: used left-hand angle
    rotate_matrix = calculate_rotate(rotate_angle, rotate_base_pnt, rotate_vector);
    if (0 !== rotate_matrix.length) {
        translation_matrix = mc_matrix_multiply(translation_matrix, rotate_matrix);
    }

    return translation_matrix;
    function get_init_matrix() {
        var init_matrix = [
            [1.0, 0.0, 0.0, 0.0],
            [0.0, 1.0, 0.0, 0.0],
            [0.0, 0.0, 1.0, 0.0],
            [0.0, 0.0, 0.0, 1.0]
        ];

        return init_matrix;
    }
    function calculate_rotate(ui_rotate_angle, arr_rotate_base_pnt, arr_rotate_vector) {
        if (ui_rotate_angle && 0 !== ui_rotate_angle && 360 !== ui_rotate_angle) {
            var rotation_pnt = [0.0, 0.0, 0.0];
            var rotation_vec = [0.0, 0.0, 0.0];

            if ("[object Array]" === Object.prototype.toString.call(arr_rotate_base_pnt) && 2 === arr_rotate_base_pnt.length) {
                rotation_pnt[0] = arr_rotate_base_pnt[0];
                rotation_pnt[1] = arr_rotate_base_pnt[1];
            }


            if ("[object Array]" === Object.prototype.toString.call(arr_rotate_vector) && 2 === arr_rotate_vector.length &&
                        0 < Math.pow(arr_rotate_vector[0], 2) + Math.pow(arr_rotate_vector[1], 2)) {
                // 取模
                var mod_vec = Math.sqrt(Math.pow(arr_rotate_vector[0], 2) + Math.pow(arr_rotate_vector[1], 2));

                rotation_vec[0] = arr_rotate_vector[0] / mod_vec;
                rotation_vec[1] = arr_rotate_vector[1] / mod_vec;
            } else {
                rotation_vec[2] = 1.0;
            }


            var u = rotation_vec[0];
            var v = rotation_vec[1];
            var w = rotation_vec[2];
            var uu = u * u;
            var uv = u * v;
            var uw = u * w;
            var vv = v * v;
            var vw = v * w;
            var ww = w * w;
            var a = rotation_pnt[0];
            var b = rotation_pnt[1];
            var c = rotation_pnt[2];
            var au = a * u;
            var av = a * v;
            var aw = a * w;
            var bu = b * u;
            var bv = b * v;
            var bw = b * w;
            var cu = c * u;
            var cv = c * v;
            var cw = c * w;

            // 弧度
            // 逆时针
            // var radian = ui_rotate_angle / 360.0 * 2 * Math.PI;
            var radian = (-ui_rotate_angle) / 360.0 * 2 * Math.PI;
            var costheta = Math.cos(radian);
            var sintheta = Math.sin(radian);
            var r_matrix = get_init_matrix();

            r_matrix[0][0] = uu + (vv + ww) * costheta;
            r_matrix[0][1] = uv * (1 - costheta) - w * sintheta;
            r_matrix[0][2] = uw * (1 - costheta) + v * sintheta;
            r_matrix[0][3] = (a * (vv + ww) - u * (bv + cw)) * (1 - costheta) + (bw - cv) * sintheta;

            r_matrix[1][0] = uv * (1 - costheta) + w * sintheta;
            r_matrix[1][1] = vv + (uu + ww) * costheta;
            r_matrix[1][2] = vw * (1 - costheta) - u * sintheta;
            r_matrix[1][3] = (b * (uu + ww) - v * (au + cw)) * (1 - costheta) + (cu - aw) * sintheta;

            r_matrix[2][0] = uw * (1 - costheta) - v * sintheta;
            r_matrix[2][1] = vw * (1 - costheta) + u * sintheta;
            r_matrix[2][2] = ww + (uu + vv) * costheta;
            r_matrix[2][3] = (c * (uu + vv) - w * (au + bv)) * (1 - costheta) + (av - bu) * sintheta;

            r_matrix[3][0] = 0;
            r_matrix[3][1] = 0;
            r_matrix[3][2] = 0;
            r_matrix[3][3] = 1;

            return r_matrix;
        }
        return [];
    }
}


/****************************简易模式*****************************************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    简易模式下的对齐 || 折叠平铺; 除第一个参数外其他参数与原函数调用一致
 * 参数:
 *    @param { Promise<String> } arr_mod 框选模组
 *    @param { Promise<String> } str_type 对齐类型 ("level")水平 (任意字符串)为垂直 不可为空
 *    @param { Promise<Number> } ui_direction 对齐方向 (任意)上/左对齐 (2)下/右对齐 不可为空
 *    @param { Promise<Number> } ui_tiled_grid 层叠偏移格子数 可为而空 为空则对齐 为数字则层叠
 * 返回:
 *    NA
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-04
 *       内容 : 所有代码
************************************************************************************************/
function mc_easy_mode_align_tile(arr_mod, str_type, ui_direction, ui_tiled_grid) {
    if ("object" !== typeof arr_mod) {
        return;
    }

    if ("number" === typeof ui_tiled_grid) {
        // 层叠平铺
        var arr_res = mc_io_tile_pos_val(arr_mod, "get");

        if (arr_res) {
            var obj_params = {
                ui_pos_i: null,
                base: arr_res,
                step: Number(ui_tiled_grid)
            };

            if ("level" === str_type) {
                // 水平平铺
                obj_params.ui_pos_i = 0;
                mc_io_tile_pos_val(arr_mod, "set", obj_params);
            } else {
                obj_params.ui_pos_i = 1;
                mc_io_tile_pos_val(arr_mod, "set", obj_params);
            }
        }
    } else {
        // 对齐
        // 处理的位置值下标
        var ui_pos_idx = null;

        if ("level" === str_type) {
            // 水平
            ui_pos_idx = 1;
        } else {
            // 垂直
            ui_pos_idx = 0;
        }

        var ui_min_max = null;

        if (2 === ui_direction) {
            // 下||右 ===  最大值处理
            ui_min_max = mc_io_align_pos_val(arr_mod, ui_pos_idx, "get", 1);
            mc_io_align_pos_val(arr_mod, ui_pos_idx, "set", ui_min_max);
        } else {
            ui_min_max = mc_io_align_pos_val(arr_mod, ui_pos_idx, "get", 0);
            mc_io_align_pos_val(arr_mod, ui_pos_idx, "set", ui_min_max);
        }
    }

    mc_easy_mode_update_pos(arr_mod);
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    简易模式下; 对齐操作时读写mod位置值
 * 参数:
 *    @param { Promise<Array> } arr_mod 框选模组
 *    @param { Promise<Number> } ui_pos_i 读取或写入时的位置值下标 === 0 || 1
 *    @param { Promise<String> } str_mode === "get" 为读取 || 其他 === 写入
 *    @param { Promise<Number> } param 读写时携带的参数(根据str_mode参数判断为读或写); param参考备注；
 * 返回:
 *    @returns { Promise<Number> } 读时 === 最大值 || 最小值; 写时 === null
 * 例子:
 *    NA
 * 备注:
 *    param 参数解释:
 *      1.读时 === 0 为获取最小值 || 其他 === 获取最大值;
 *      2.写时 === 直接写入的位置值
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-04
 *       内容 : 所有代码
************************************************************************************************/
function mc_io_align_pos_val(arr_mod, ui_pos_i, str_mode, param) {
    var ui_len = arr_mod.length;
    var ui_min_max = null;

    for (var ui_i_align = 0; ui_i_align < ui_len; ui_i_align++) {
        var $obj_ele = arr_mod[ui_i_align];
        var obj_ele = $obj_ele[0];

        if (0 === $obj_ele.length) {
            continue;
        }

        // var $obj_pos =  $obj_ele.children(".mod_msg_box").children(".mod_pot");
        var $obj_pos = mc_get_appoint_obj($obj_ele, "mod_pot", true);

        if (0 === $obj_pos.length) {
            continue;
        }

        var str_pos = $obj_pos.text();

        if (str_pos) {
            if ("get" === str_mode) {
                // get
                var ui_pos_val = Number(str_pos.split(",")[ui_pos_i]);

                if (null === ui_min_max) {
                    ui_min_max = ui_pos_val;
                }

                if (0 === param) {
                    // 获取最小值
                    if (ui_pos_val < ui_min_max) {
                        ui_min_max = ui_pos_val;
                    }
                } else {
                    if (ui_pos_val > ui_min_max) {
                        ui_min_max = ui_pos_val;
                    }
                }
            } else {
                // set
                var arr_pos_val = str_pos.split(",");

                arr_pos_val[ui_pos_i] = param;
                $obj_pos[0].innerText = arr_pos_val.join(",");

                obj_ele.style.zIndex = ui_i_align;
                obj_ele.setAttribute("addzindex", ui_i_align);
            }
        }
    }

    return ui_min_max;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    简易模式下; 平铺操作时读写mod位置值
 * 参数:
 *    @param { Promise<Array> } arr_mod 框选模组
 *    @param { Promise<String> } str_mode === "get" 为读取 || 其他 === 写入
 *    @param { Promise<Object> } params 仅在写时携带的参数(根据str_mode参数判断为读或写); params 参考备注；
 * 返回:
 *    @returns { Promise<Array> } 返回框选的位置值数组; 读时 === [最小X值, 最小Y值] || 写时 === [null , null]
 * 例子:
 *    NA
 * 备注:
 *    params 参数对象属性解释：
 *      1. ui_pos_i === 需要修改的位置值下标;
 *      2. base === 基准值数组 === 读取时返回的值;
 *      3. step === 层叠平铺的步进值;
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-04
 *       内容 : 所有代码
************************************************************************************************/
function mc_io_tile_pos_val(arr_mod, str_mode, params) {
    var ui_len = arr_mod.length;
    var ui_min_x = null;
    var ui_min_y = null;
    var obj_param = params;

    for (var ui_i_tile = 0; ui_i_tile < ui_len; ui_i_tile++) {
        var $obj_ele = arr_mod[ui_i_tile];
        var obj_ele = $obj_ele[0];

        if (0 === $obj_ele.length) {
            continue;
        }

        // var $obj_pos = $obj_ele.children(".mod_msg_box").children(".mod_pot");
        var $obj_pos = mc_get_appoint_obj($obj_ele, "mod_pot", true);

        if (0 === $obj_pos.length) {
            continue;
        }

        var str_pos = $obj_pos.text();

        if (!str_pos) {
            continue;
        }


        if ("get" === str_mode) {
            var arr_pos = str_pos.split(",");
            var ui_x = Number(arr_pos[0]);
            var ui_y = Number(arr_pos[1]);

            if (null === ui_min_x) {
                ui_min_x = ui_x;
            }

            if (null === ui_min_y) {
                ui_min_y = ui_y;
            }

            // change min x y
            if (ui_x < ui_min_x) {
                ui_min_x = ui_x;
            }

            if (ui_y < ui_min_y) {
                ui_min_y = ui_y;
            }
        } else {
            // set
            var arr_pos_val = str_pos.split(",");
            var ui_cur_step = (obj_param.step * ui_i_tile);

            arr_pos_val[0] = obj_param.base[0];
            arr_pos_val[1] = obj_param.base[1];
            arr_pos_val[obj_param.ui_pos_i] = obj_param.base[obj_param.ui_pos_i] + ui_cur_step;

            $obj_pos[0].innerText = arr_pos_val.join(",");

            obj_ele.style.zIndex = ui_i_tile;
            obj_ele.setAttribute("addzindex", ui_i_tile);
        }
    }

    return [ui_min_x, ui_min_y];
}

// 坐标尺缩放更新
function mc_zoom_coordinate_grid(ui_scale) {
    if (!b_create_grid) {
        if (has_ruler_and_method("zoom_coordinate_grid")) {
            obj_box_coordinate_ruler.zoom_coordinate_grid(ui_scale);
        }
    }
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取第一个模组的大小
 * 参数:
 *    @param { Promise<String> } obj_wrap 包裹模组的外层对象
 * 返回:
 *    @returns { Promise<Object> } 模组宽高 { W, H }; 默认1,1
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-09
 *       内容 : 所有代码
************************************************************************************************/
function get_fisrt_mod_size(obj_wrap) {
    var obj_first = {};

    if (obj_wrap && (obj_first = obj_wrap.querySelector(".mc_mod"))) {
        return {
            W: Number(obj_first.getAttribute("mod_wg")),
            H: Number(obj_first.getAttribute("mod_hg"))
        };
    }

    return {
        W: 1,
        H: 1
    };
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取边界格子数值; 简易模式
 * 参数:
 *    @param { Promise<Number> } ui_size 原始边界值
 *    @param { Promise<Number> } obj_first_wh 第一个模组的宽高值
 * 返回:
 *    @returns { Promise<Number> } 简易模式 === true 返回新的边界值 || === false 时返回参数边界值；
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-09
 *       内容 : 所有代码
************************************************************************************************/
function get_boundary_grid_num(ui_size, obj_first_wh) {
    if (obj_item_checkbox_easy_mode.get_dom_val() && has_ruler_and_method("update_coordinate_grid")) {
        return ui_size / ui_easy_mode_size * obj_first_wh;
    }

    return ui_size;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    获取显示名称块html串
 * 参数:
 *    @param { Promise<String> } str_name 块值
 *    @param { Promise<String> } str_display 显示隐藏样式 可为空
 * 返回:
 *    @returns { Promise<String> } 不带值div串 || 带值的div串
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-24
 *       内容 : 所有代码
 *    2. 类型 : 添加
 *       作者 : 陈小荟
 *       时间 : 2021-01-23
 *       内容 : 显示隐藏样式添加
************************************************************************************************/
function get_show_name_html(str_name, str_display) {
    var str_style_display = "";

    if ("string" === typeof str_display && 0 !== str_display.length) {
        str_style_display = "style=" + str_display;
    }
    if ("string" !== typeof str_name) {
        return "<div class='mod_show_name' " + str_style_display + ">" + " " + "</div>";
    }
    var str_html = "<div class='mod_show_name' " + str_style_display + ">" + str_name + "</div>";

    return str_html;
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    更新显示名称值
 * 参数:
 *    @param { Promise<String> } id === 模块的属性为 mod_id 的值(数据源名称)
 *    @param { Promise<String> } val 新名称
 * 返回:
 *    @returns { Promise<Boolean> } true === 设置成功 || false === 失败
 * 例子:
 *    NA
 * 备注:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 巫昭雯
 *       时间 : 2020-12-24
 *       内容 : 所有代码
************************************************************************************************/
function update_show_name_val(id, val) {
    if ("string" !== typeof id || "string" !== typeof val) {
        return false;
    }

    var arr_mod = $("#mod_box_next .mc_mod");
    var arr_len = arr_mod.length;

    if (0 === arr_len) {
        return false;
    }

    var arr_mod_cur = $("#mod_box_next .mc_mod[mod_id=" + id + "]");

    if (0 === arr_mod_cur.length) {
        return false;
    }

    arr_mod_cur.children(".mod_msg_box").children(".mod_show_name").text(val);

    return true;
}

/****************************模块组合*************************************************************/
/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    模块组合-拆分-编辑
 * 参数:
 *    无
 * 返回:
 *    NA
 * 修改:
 *    1. 类型 : 创建
 *       作者 : 陈小荟
 *       时间 : 2021.04.16
 *       内容 : 所有代码
************************************************************************************************/
function mc_module_compose() {
    // 组合模块信息 （信息大小为格子数）
    // {
    //     "S1_P1_H2:P1":{
    //         obj_module_data:模块字串参数对象,
    //         arr_boundary_potsize:组合模块偏移大小信息,
    //         str_key:"组合块key对应连线数据key",
    //         str_compose_id:"组合块id",
    //         arr_statr_pot:[初次构建时外接矩形位置]
    //     }
    // }
    var o_compose_module_msg = {};
    // 当前正在编辑组合块KEY
    var edit_key = false;

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    组合
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     *    @param { Promise<Object> } obj_module_data 构建模块字串参数数组{id:{msg},,}
     *    @param { Promise<Array> } arr_boundary 整体位置大小信息（格子数) [X,Y,W,H]
     *    @param { Promise<String> } str_id 组合模块id（可为空 撤销回撤传入）
     * 返回：
     *    @return { Promise<Object> }
     *    null 参数/数据有误
     *    {
     *      str_html: str_html, // 组合块HTML字串
     *      str_id: str_id // 组合块id
     *      }
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.set_module_compose = function (str_key,obj_module_data,arr_boundary,str_id) {
        if ("[object String]" !== Object.prototype.toString.call(str_key)) {
            return null;
        }
        if ("[object Object]" !== Object.prototype.toString.call(obj_module_data)) {
            return null;
        }
        if ("[object Array]" !== Object.prototype.toString.call(arr_boundary)) {
            return null;
        }
        // 存在当前需要构建组合模块 删除旧模块 (编辑回撤重做)
        if (str_id && document.getElementById(str_id)) {
            $("#" + str_id).remove();
        }

        var ui_grid = Number(document.getElementById("mod_box_next").getAttribute("grid_w"));
        var str_module_first_key = Object.keys(obj_module_data)[0];
        var obj_param = obj_module_data[str_module_first_key];
        var arr_indo_disp_style = mc_info_disp_style();
        var ui_child_transform = 1 / (ui_mod_box_scale / 100);
        var ui_width = arr_boundary[2];
        var ui_height = arr_boundary[3];
        var str_size = ui_width + "X" + ui_height;
        var str_pot = arr_boundary[0] + "," + arr_boundary[1];
        var str_style = "background-color:#8C9BF0;left:" + arr_boundary[0] * ui_grid + "px;top:" + arr_boundary[1] * ui_grid + "px;width:" + ui_width * ui_grid + "px;height:" + ui_height * ui_grid + "px;";

        str_id = str_id || "mod" + mc_get_id();
        // save str_size str_pot
        mc_save_undom_module_msg(str_id, str_size, str_pot);

        var str_show_name_html = get_show_name_html(obj_param.show_name, arr_indo_disp_style[0]);
        var str_ctrlchip_html = "<div class='chip_name' style='" + arr_indo_disp_style[1] + "'>" + obj_param.ctrlchip_name + "</div>";
        var str_card_index = "<div class='mc_mod_right_bto' style='transform:scale(" + ui_child_transform + ");'><div class='card_idx' style='" + arr_indo_disp_style[6] + "'>" + obj_param.card_idx + "</div></div>";
        var str_lock_tip = "<div class='mc_mod_right_top' style='transform:scale(" + ui_child_transform + ");'><div class='mc_lock_icon icon-lock'></div></div>";
        var str_compose_key = obj_param.card_idx + ":" + obj_param.val;
        var str_module_box_attr = "class='mc_mod mc_compose_mod' compose_key='" + str_compose_key + "' tabindex='-1' mod_id='" + obj_param.name + "' style='" + str_style + "' mod_wg='" + ui_width + "' mod_hg='" + ui_height + "' " + str_mod_attr_easy_mode + "=false";
        var str_msg_box_html = "<div class='mod_msg_box' style='transform:scale(" + ui_child_transform + ");'>" + str_show_name_html + str_ctrlchip_html + "<div class='mod_size' style='display:none;'>" + str_size + "</div><div class='mod_pot' style='" + arr_indo_disp_style[2] + "'>" + str_pot + "</div></div>";
        var str_box_html = "<div id='" + str_id + "' " + str_module_box_attr + " onmousedown='mc_mod_mousedown(event,this)'>";

        if (!b_istouch) {
            str_box_html = "<div id='" + str_id + "' " + str_module_box_attr + " ontouchstart='mc_mod_mousedown(event,this)'>";
        }
        var str_html = str_box_html + str_msg_box_html + "<div class='mod_hub_box' style='transform:scale(" + ui_child_transform + ");'><div class='mod_hub_div' style='" + arr_indo_disp_style[4] + "'>" + obj_param.val + "</div></div>" + str_card_index + str_lock_tip + "</div>";

        // save data
        this.update_compose_data(str_key,{
            obj_module_data: obj_module_data,
            arr_boundary_potsize: arr_boundary,
            str_key: str_key,
            str_compose_id: str_id,
            // 初次构建时外接位置
            arr_statr_pot: [arr_boundary[0],arr_boundary[1]]
        },"add");
        // this.update_module_data(str_key,obj_module_data);


        return {
            str_html: str_html,
            str_id: str_id
        };
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    拆分
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     *    @param { Promise<Boolean> } b_undelete 是否删除组合块数据 可为空 默认删除 true=不删除
     * 返回：
     *    @return { Promise<Object> }
     *    null 参数/数据有误
     *    obj_compose_data 当前拆分组合块数据
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.set_module_split = function (str_key,b_undelete) {
        if ("[object String]" !== Object.prototype.toString.call(str_key)) {
            return null;
        }
        var obj_data = o_compose_module_msg[str_key];

        if ("[object Object]" !== Object.prototype.toString.call(obj_data)) {
            return null;
        }

        // 更新组合块偏移信息
        var obj_compose_data = this.updata_compose_blk_msg(str_key);

        if (!obj_compose_data) {
            return null;
        }
        obj_compose_data = JSON.parse(JSON.stringify(obj_compose_data));

        // 创建组合小块（外部）
        // 删除组合块
        document.getElementById(obj_data.str_compose_id).remove();
        // 删除组合块对应数据
        if (!b_undelete) {
            this.update_compose_data(str_key,false,"delete");
        }
        return obj_compose_data;
    };


    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    切换编辑开关
     * 参数:
     *    无
     * 返回：
     *    @return { Promise<Boolean> }
     *    当前编辑状态
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.set_switch_edit = function () {
        b_progress_edit = b_progress_edit ? false : true;
        return b_progress_edit;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    获取当前组合块keyList
     * 参数:
     *    无
     * 返回：
     *    @return { Promise<Array> }
     *    获取当前组合块keyList
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.get_compose_list = function () {
        var arr_key = Object.keys(o_compose_module_msg);

        arr_key = mc_filter_tool(function (item) {
            return "[object Object]" === Object.prototype.toString.call(o_compose_module_msg[item]);
        },arr_key);
        return arr_key;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    获取指定组合块数据
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     * 返回：
     *    @return { Promise<Object> }
     *     null 参数/数据有误
     *     obj_compose_data 当前组合块数据
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.get_compose_data = function (str_key) {
        if ("[object String]" !== Object.prototype.toString.call(str_key)) {
            return null;
        }
        return o_compose_module_msg[str_key];
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    获取当前编辑组合块key
     * 参数:
     *    无
     * 返回：
     *    @return { Promise<String> }
     *    当前编辑组合块key
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.get_edit_key = function () {
        return edit_key;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    更新当前编辑KEY
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     * 返回：
     *    @return { Promise<Boolean> }
     *     false 参数/数据有误
     *     true 设置成功
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.update_edit_key = function (str_key) {
        if ("[object String]" !== Object.prototype.toString.call(str_key)) {
            return false;
        }
        edit_key = str_key;
        return true;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    更新组合存储数据(添加 删除)
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     *    @param { Promise<Object> } data 更新的数据 可为空 delete时
     *    @param { Promise<String> } update_type 更新类型 add/delete
     * 返回：
     *    @return { Promise<Boolean> }
     *     false 参数/数据有误
     *     true 更新成功
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.update_compose_data = function (str_key,data,update_type) {
        // add
        if ("add" === update_type ) {
            o_compose_module_msg[str_key] = data;
        }
        // delete
        if ("delete" === update_type && o_compose_module_msg[str_key]) {
            o_compose_module_msg[str_key] = null;
        }
        return true;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    更新组合信息key (更改连线)
     * 参数:
     *    @param { Promise<String> } str_old_key 更新队列key
     *    @param { Promise<String> } str_key 新key
     * 返回：
     *    @return { Promise<Boolean> }
     *     false 参数/数据有误
     *     true 更新成功
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.update_compose_key = function (str_old_key,str_key) {
        if ("[object String]" !== Object.prototype.toString.call(str_old_key) || "[object String]" !== Object.prototype.toString.call(str_key)) {
            return false;
        }
        if (str_old_key === str_key) {
            return false;
        }
        var obj_data = o_compose_module_msg[str_old_key];
        var str_id = obj_data.str_compose_id;

        if (obj_data) {
            var obj_compose = document.getElementById(str_id);

            o_compose_module_msg[str_key] = obj_data;
            o_compose_module_msg[str_key].str_key = str_key;
            // 添加更新标识
            o_compose_module_msg[str_key].update_key = true;
            o_compose_module_msg[str_old_key] = null;
            // 更新元素compose_key标识
            if (obj_compose) {
                obj_compose.setAttribute("compose_key",str_key);
            }
        }
        return true;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    更新组合模块中各模块left、top、list_idx、val(比较组合块更新)
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     * 返回：
     *    @return { Promise<Object> }
     *     null 参数/数据有误
     *     obj_data 更新后数据
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.updata_compose_blk_msg = function (str_key) {
        if ("[object String]" !== Object.prototype.toString.call(str_key)) {
            return null;
        }
        var obj_data = o_compose_module_msg[str_key];

        if (!obj_data) {
            return null;
        }
        // 是否更新KEY
        var b_update_key = obj_data.update_key;
        // 是否更新偏移
        var b_update_offset = true;
        var arr_compose_pot = mc_get_child_pot_size(document.getElementById(obj_data.str_compose_id)).str_pot.split(",");
        var arr_statr_pot = obj_data.arr_statr_pot;
        var ui_dvalue_x = Number(arr_compose_pot[0]) - Number(arr_statr_pot[0]);
        var ui_dvalue_y = Number(arr_compose_pot[1]) - Number(arr_statr_pot[1]);
        // 模块字串参数对象
        var obj_module_data = obj_data.obj_module_data;
        var arr_key = Object.keys(obj_module_data);
        var ary_key = str_key.split(":");

        if (0 === ui_dvalue_x && 0 === ui_dvalue_y) {
            b_update_offset = false;
        }

        // 无需更新
        if (!b_update_offset && !b_update_key) {
            return obj_data;
        }

        for (var index = 0; index < arr_key.length; index++) {
            var element = arr_key[index];
            var obj_blk_data = obj_module_data[element];

            // 更新模块偏移
            if (b_update_offset) {
                obj_blk_data.left = String(Number(obj_blk_data.left) + ui_dvalue_x);
                obj_blk_data.top = String(Number(obj_blk_data.top) + ui_dvalue_y);
            }
            // 更新KEY
            if (b_update_key) {
                obj_blk_data.card_idx = ary_key[0];
                obj_blk_data.val = ary_key[1];
            }
        }
        return obj_data;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    更新组合模块中各模块偏移信息(获取元素 直接更新)
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     * 返回：
     *    @return { Promise<Boolean> }
     *     false 参数/数据有误
     *     true 更新成功
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.update_compose_blk_offset = function (str_key) {
        if ("[object String]" !== Object.prototype.toString.call(str_key)) {
            return false;
        }
        var obj_data = o_compose_module_msg[str_key];

        if (obj_data) {
            var obj_module_data = obj_data.obj_module_data;
            var arr_key = Object.keys(obj_module_data);

            for (var index = 0; index < arr_key.length; index++) {
                var element = arr_key[index];
                var obj_blk_data = obj_module_data[element];
                var obj_js = document.getElementById(element);
                var obj_msg = mc_get_child_pot_size(obj_js);
                var arr_pot = obj_msg.str_pot.split(",");

                obj_blk_data.left = Number(arr_pot[0]);
                obj_blk_data.top = Number(arr_pot[1]);
            }
        }
        return true;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    更新组合块信息(偏移、大小) （编辑）
     * 参数:
     *    @param { Promise<String> } str_key key:S1_P1_H2:P1 当前选择组合连线队列KEY 组合块"compose_key"标识
     *    @param { Promise<Array> } arr_offset 偏移
     *    @param { Promise<Array> } arr_size 大小
     *    @param { Promise<Boolean> } b_update_start_pot 是否更新起始偏移
     * 返回：
     *    @return { Promise<Array> }
     *     [] 参数/数据有误
     *     obj_data.arr_boundary_potsize 组合块外接偏移大小 [X,Y,W,H]
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.04.16
     *      内容 : 所有代码
     ************************************************************************************************/
    this.update_compose_msg = function (str_key,arr_offset,arr_size,b_update_start_pot) {
        var obj_data = this.get_compose_data(str_key);

        if (!obj_data) {
            return [];
        }
        if ("[object Array]" === Object.prototype.toString.call(arr_offset)) {
            obj_data.arr_boundary_potsize[0] = arr_offset[0];
            obj_data.arr_boundary_potsize[1] = arr_offset[1];
        }
        if ("[object Array]" === Object.prototype.toString.call(arr_size)) {
            obj_data.arr_boundary_potsize[2] = arr_size[0];
            obj_data.arr_boundary_potsize[3] = arr_size[1];
        }
        if (b_update_start_pot) {
            obj_data.arr_statr_pot = arr_offset;
        }
        return obj_data.arr_boundary_potsize;
    };

    /************************************************************************************************
     * 类型:
     *    函数
     * 功能:
     *    初始化组合卡数据
     * 参数:
     *    NA
     * 返回：
     *    无
     * 修改:
     *   1. 类型 : 创建
     *      作者 : 陈小荟
     *      时间 : 2021.05.12
     *      内容 : 所有代码
     ************************************************************************************************/
    this.init_compose_data = function () {
        o_compose_module_msg = {};
        edit_key = false;
    };
}

/************************************************************************************************
 * 类型:
 *    函数
 * 功能:
 *    编辑模式下 拖动小块更新外接虚线框处理
 * 参数:
 *    @param { Promise<Number> } ui_w 移动边框 宽 以下参数均为实际长度
 *    @param { Promise<Number> } ui_h 移动边框 高
 *    @param { Promise<Number> } ui_x 移动边框 left
 *    @param { Promise<Number> } ui_y 移动边框 top
 * 返回：
 *    @return { Promise<Boolean> }
 *    false 参数/数据有误
 *    true 设置成功
 * 修改:
 *   1. 类型 : 创建
 *      作者 : 陈小荟
 *      时间 : 2021.04.16
 *      内容 : 所有代码
 ************************************************************************************************/
function mc_edit_boundary_handle(ui_w,ui_h,ui_x,ui_y) {
    if (!b_progress_edit) {
        return false;
    }
    var obj_edit_border = document.getElementById("mc_edit_border");
    var obj_compose_list = document.getElementsByClassName("compose_edit");
    var str_basis_style = "position: absolute;border: 10px dashed gray;";

    if (!obj_edit_border || 0 === obj_compose_list.length) {
        return false;
    }

    if (arr_select_mod.length === obj_compose_list.length) {
        // 移动框偏移大小 = 当前编辑虚线框
        obj_edit_border.style.cssText = str_basis_style + "left:" + ui_x + "px;top:" + ui_y + "px;width:" + ui_w + "px;height:" + ui_h + "px;";
        return true;
    }

    var ui_min_x = ui_x;
    var ui_min_y = ui_y;
    var ui_max_x = ui_x + ui_w;
    var ui_max_y = ui_y + ui_h;

    for (var i = 0; i < obj_compose_list.length; i++) {
        var obj_js = obj_compose_list[i];

        if ($(obj_js).hasClass("selected")) {
            continue;
        }
        var arr_size = mc_get_optsize_msg(obj_js, true);
        var arr_pot = mc_get_optsize_msg(obj_js);
        var u_min_x = arr_pot[0];
        var u_min_y = arr_pot[1];
        var u_max_x = arr_size[0] + u_min_x;
        var u_max_y = arr_size[1] + u_min_y;

        ui_min_x = u_min_x < ui_min_x ? u_min_x : ui_min_x;
        ui_min_y = u_min_y < ui_min_y ? u_min_y : ui_min_y;
        ui_max_x = u_max_x > ui_max_x ? u_max_x : ui_max_x;
        ui_max_y = u_max_y > ui_max_y ? u_max_y : ui_max_y;
    }
    obj_edit_border.style.cssText = str_basis_style + "left:" + ui_min_x + "px;top:" + ui_min_y + "px;width:" + (ui_max_x - ui_min_x) + "px;height:" + (ui_max_y - ui_min_y) + "px;";
    return true;
}
